提出 #17569521


ソースコード 拡げる

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <atcoder/modint>

constexpr int M = 45;

namespace ac = atcoder;
using mint = ac::modint998244353;

// *(1 + ax)
void mul(std::vector<mint>& f, mint a) {
    if (a == 0) return;

    f.push_back(0);
    for (int i = (int)f.size() - 1; i > 0; --i) {
        f[i] += f[i - 1] * a;
    }
}

// /(1 + ax)
void div(std::vector<mint>& f, mint a) {
    if (a == 0) return;

    for (int i = 1; i < (int)f.size(); ++i) {
        f[i] -= f[i - 1] * a;
    }
    f.pop_back();
}

void solve() {
    int n, q;
    std::cin >> n >> q;

    // 階乗の前計算
    std::vector<mint> facts(n + 1, 1);
    for (int i = 2; i <= n; ++i) facts[i] = facts[i - 1] * i;

    std::vector<int> xs(n);
    for (auto& x : xs) std::cin >> x;

    std::vector<std::pair<int, int>> ps(q);
    for (auto& [l, r] : ps) std::cin >> l >> r;

    // Mo's algorithm: クエリを並び替える
    std::vector<int> idxs(q);
    std::iota(idxs.begin(), idxs.end(), 0);
    std::sort(idxs.begin(), idxs.end(),
              [&](auto i, auto j) {
                  auto [li, ri] = ps[i];
                  auto [lj, rj] = ps[j];

                  if (li / M == lj / M) {
                      return ri < rj;
                  } else {
                      return li < lj;
                  }
              });

    int l = 0, r = 0;
    std::vector<mint> f{1};
    std::vector<int> cnt(n, 0);

    std::vector<mint> ans(q, 0);
    for (auto i : idxs) {
        auto [nl, nr] = ps[i];

        // extend
        while (nl < l) {
            --l;
            div(f, cnt[xs[l]]);
            ++cnt[xs[l]];
            mul(f, cnt[xs[l]]);
        }
        while (r < nr) {
            div(f, cnt[xs[r]]);
            ++cnt[xs[r]];
            mul(f, cnt[xs[r]]);
            ++r;
        }

        // shrink
        while (l < nl) {
            div(f, cnt[xs[l]]);
            --cnt[xs[l]];
            mul(f, cnt[xs[l]]);
            ++l;
        }
        while (nr < r) {
            --r;
            div(f, cnt[xs[r]]);
            --cnt[xs[r]];
            mul(f, cnt[xs[r]]);
        }

        for (int k = 0; k < (int)f.size(); ++k) {
            ans[i] += f[k] * facts[n - k] * mint(-1).pow(k);
        }
    }

    for (auto a : ans) std::cout << a.val() << "\n";
}

int main() {
    std::cin.tie(nullptr);
    std::ios::sync_with_stdio(false);
 
    solve();
 
    return 0;
}

提出情報

提出日時
問題 F - Count Permutations Many Times
ユーザ Tiramister
言語 C++ (GCC 9.2.1)
得点 800
コード長 2554 Byte
結果 AC
実行時間 345 ms
メモリ 3708 KiB

ジャッジ結果

セット名 Sample All
得点 / 配点 0 / 0 800 / 800
結果
AC × 3
AC × 28
セット名 テストケース
Sample sample-01.txt, sample-02.txt, sample-03.txt
All 01-01.txt, 01-02.txt, 01-03.txt, 01-04.txt, 01-05.txt, 01-06.txt, 01-07.txt, 01-08.txt, 01-09.txt, 01-10.txt, 01-11.txt, 01-12.txt, 01-13.txt, 01-14.txt, 01-15.txt, 01-16.txt, 01-17.txt, 01-18.txt, 01-19.txt, 01-20.txt, 01-21.txt, 01-22.txt, 01-23.txt, 01-24.txt, 01-25.txt, sample-01.txt, sample-02.txt, sample-03.txt
ケース名 結果 実行時間 メモリ
01-01.txt AC 9 ms 3536 KiB
01-02.txt AC 9 ms 3628 KiB
01-03.txt AC 4 ms 3660 KiB
01-04.txt AC 226 ms 3616 KiB
01-05.txt AC 106 ms 3656 KiB
01-06.txt AC 295 ms 3636 KiB
01-07.txt AC 181 ms 3504 KiB
01-08.txt AC 320 ms 3692 KiB
01-09.txt AC 239 ms 3708 KiB
01-10.txt AC 334 ms 3628 KiB
01-11.txt AC 254 ms 3560 KiB
01-12.txt AC 345 ms 3576 KiB
01-13.txt AC 284 ms 3672 KiB
01-14.txt AC 337 ms 3672 KiB
01-15.txt AC 334 ms 3556 KiB
01-16.txt AC 332 ms 3616 KiB
01-17.txt AC 329 ms 3516 KiB
01-18.txt AC 332 ms 3576 KiB
01-19.txt AC 330 ms 3512 KiB
01-20.txt AC 326 ms 3560 KiB
01-21.txt AC 337 ms 3628 KiB
01-22.txt AC 329 ms 3612 KiB
01-23.txt AC 338 ms 3628 KiB
01-24.txt AC 328 ms 3700 KiB
01-25.txt AC 337 ms 3680 KiB
sample-01.txt AC 2 ms 3596 KiB
sample-02.txt AC 2 ms 3492 KiB
sample-03.txt AC 3 ms 3488 KiB