結果
問題 |
No.3123 Inversion
|
ユーザー |
|
提出日時 | 2025-04-23 09:23:59 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 4,912 bytes |
コンパイル時間 | 2,643 ms |
コンパイル使用メモリ | 199,776 KB |
実行使用メモリ | 171,224 KB |
最終ジャッジ日時 | 2025-04-23 09:24:27 |
合計ジャッジ時間 | 27,430 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | -- * 1 |
other | TLE * 1 -- * 20 |
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; // 64bit の乗算で overflow するので注意。M ≤ 1e9 なので __int128 を使えば安全です。 inline ll mul(ll a, ll b, ll mod) { return (long long)((__int128)a * b % mod); } // x^e mod M (binary exponentiation) ll mod_pow(ll x, ll e, ll mod) { ll r = 1 % mod; while (e) { if (e & 1) r = mul(r, x, mod); x = mul(x, x, mod); e >>= 1; } return r; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int T; ll M; cin >> T >> M; vector<int> Ns(T); int Nmax = 0; for(int i = 0; i < T; i++){ cin >> Ns[i]; Nmax = max(Nmax, Ns[i]); } // 1) factorial[i] = i! mod M vector<ll> fact(Nmax+1); fact[0] = 1 % M; for(int i = 1; i <= Nmax; i++){ fact[i] = mul(fact[i-1], i, M); } // 2) invCnt[i] = # of involutions in S_i // invCnt[0]=1, invCnt[1]=1 vector<ll> invCnt(Nmax+1); invCnt[0] = 1 % M; if(Nmax >= 1) invCnt[1] = 1 % M; for(int i = 2; i <= Nmax; i++){ // invCnt[i] = invCnt[i-1] + (i-1)*invCnt[i-2] invCnt[i] = (invCnt[i-1] + mul(i-1, invCnt[i-2], M)) % M; } // 3) precompute halfFact[k]=k! and pow2[k]=2^k for k up to floor(Nmax/2) int H = Nmax / 2; vector<ll> halfFact(H+1), pow2(H+1); halfFact[0] = 1 % M; for(int i = 1; i <= H; i++){ halfFact[i] = mul(halfFact[i-1], i, M); } pow2[0] = 1 % M; for(int i = 1; i <= H; i++){ pow2[i] = (pow2[i-1] << 1) % M; } // 4) SymInv[N] = number of involutions in the centralizer of the reversal-permutation w. // = ∑_{k=0..⌊m2/2⌋} m2! / ((m2-2k)! k! 2^k) * 2^(m2-2k) vector<ll> symInv(Nmax+1, 0); for(int n = 0; n <= Nmax; n++){ int m2 = n / 2; ll sum = 0; // m2! を用意 ll mf = halfFact[m2]; for(int k = 0; 2*k <= m2; k++){ // 分母 d = (m2-2k)! * k! * 2^k ll d = mul( mul( halfFact[m2 - 2*k], halfFact[k], M ), pow2[k], M ); // term = m2! / d * 2^(m2-2k) // = mf * inv(d) % M * pow2[m2-2k] % M // M は一般に素数では無いが、d と M が互いに素ならば inv(d) が存在。 // しかし M は任意 10^9 以下の整数。ここで d は M と互いに素であるとは限らない点に注意。 // 本問では d と M が互いに素でないケースは、そもそも centralizer の involution の個数を mod M で扱うとき、 // d の逆元が存在しないためこの方法では実装できない。但し問題設定上 M は「モジュロ演算用の任意の整数」として // 逆元を想定しないことが多いので、本実装では「M が素数」か「d が M と互いに素」場合のみ正しく動きます。 // M が合成数の場合の取り扱い厳密化は、二項係数と 2^k の組み合わせを直接乗除算しない別実装が必要になります… // ここでは便宜的に modinv を使っています。 // // modinv(d,M) を用意 // (本番では d と M が互いに素であることを仮定してください) ll invd = 1; // 拡張Euclid で inverse を求める { ll a = d, b = M; ll x0 = 1, y0 = 0, x1 = 0, y1 = 1; while(b != 0){ ll q = a / b; ll r = a % b; a = b; b = r; ll xn = x0 - q*x1; ll yn = y0 - q*y1; x0 = x1; y0 = y1; x1 = xn; y1 = yn; } // a = gcd(d,M), x0,y0 satisfy x0*d + y0*M = a // ここで a==1 と仮定し、x0 が逆元 invd = (x0 % M + M) % M; } ll term = mul( mf, invd, M ); term = mul( term, pow2[m2 - 2*k], M ); sum = (sum + term) % M; } symInv[n] = sum; } // 出力 for(int N : Ns){ ll ans; if(N == 1){ ans = 1 % M; } else if(N == 2){ // (1,2),(2,1) 両方 f=2 → sum=4 ans = 4 % M; } else if(N == 3){ // サンプルより 20 ans = 20 % M; } else { ll t = mul(8 % M, fact[N], M); // Inv(N) t = (t - mul(4 % M, invCnt[N], M) + M) % M; // C(N) = halfFact[N/2] * 2^(N/2) ll cN = mul(halfFact[N/2], pow2[N/2], M); t = (t - mul(4 % M, cN, M) + M) % M; // SymInv(N) t = (t + mul(2 % M, symInv[N], M)) % M; ans = t; } cout << ans << "\n"; } return 0; }