题目大意
求$$f_i=(i-1)!\sum_{j=0}^{i-1}(i-j)^2{f_j\over j!}$$
简要题解
为求$f_i$我们需要知道$f_0,\cdots,f_{i-1}$,考虑cdq分治,把卷积拆开成关于已知的$f_i$和还没计算出来的部分,发现已知部分还是卷积形式,求出来累加上去就好。
此外还写了个求原根,暴力枚举原根$a$,然后判断是否只有$a^{p-1}=1(\mod p)$而$a^{p-1\over p_i}=1(\mod p)$皆不成立,其中$p_i$是$p$的所有素因子。
#include <bits/stdc++.h> using namespace std; namespace my_header { #define pb push_back #define mp make_pair #define pii pair<int, int> #define vec vector<int> #define pc putchar #define clr(t) memset(t, 0, sizeof t) #define pse(t, v) memset(t, v, sizeof t) #define bl puts("") #define wn(x) wr(x), bl #define ws(x) wr(x), pc(‘ ‘) const int INF = 0x3f3f3f3f; typedef long long LL; typedef double DB; inline char gchar() { char ret = getchar(); for(; (ret == ‘\n‘ || ret == ‘\r‘ || ret == ‘ ‘) && ret != EOF; ret = getchar()); return ret; } template<class T> inline void fr(T &ret, char c = ‘ ‘, int flg = 1) { for(c = getchar(); (c < ‘0‘ || ‘9‘ < c) && c != ‘-‘; c = getchar()); if (c == ‘-‘) { flg = -1; c = getchar(); } for(ret = 0; ‘0‘ <= c && c <= ‘9‘; c = getchar()) ret = ret * 10 + c - ‘0‘; ret = ret * flg; } inline int fr() { int t; fr(t); return t; } template<class T> inline void fr(T&a, T&b) { fr(a), fr(b); } template<class T> inline void fr(T&a, T&b, T&c) { fr(a), fr(b), fr(c); } template<class T> inline char wr(T a, int b = 10, bool p = 1) { return a < 0 ? pc(‘-‘), wr(-a, b, 0) : (a == 0 ? (p ? pc(‘0‘) : p) : (wr(a/b, b, 0), pc(‘0‘ + a % b))); } template<class T> inline void wt(T a) { wn(a); } template<class T> inline void wt(T a, T b) { ws(a), wn(b); } template<class T> inline void wt(T a, T b, T c) { ws(a), ws(b), wn(c); } template<class T> inline void wt(T a, T b, T c, T d) { ws(a), ws(b), ws(c), wn(d); } template<class T> inline T gcd(T a, T b) { return b == 0 ? a : gcd(b, a % b); } template<class T> inline T fpw(T b, T i, T _m, T r = 1) { for(; i; i >>= 1, b = b * b % _m) if(i & 1) r = r * b % _m; return r; } }; using namespace my_header; const int MAXN = 2e6 + 100; namespace NTT { const int MOD = 998244353; int inv[MAXN]; vec getPrime(vec&isPrime, int rng = 1000000) { isPrime.resize(rng); fill(isPrime.begin(), isPrime.end(), 1); vec pri; isPrime[0] = isPrime[1] = 0; inv[1] = 1; for (int i = 2; i < rng; ++i) { if (isPrime[i]) { pri.pb(i); inv[i] = fpw((LL)i, MOD-2LL, (LL)MOD); } for (int j = 0; j < (int)pri.size() && pri[j] * 1LL * i < rng; ++j) { isPrime[i * 1LL * pri[j]] = 0; inv[i * 1LL * pri[j]] = 1LL * inv[i] * inv[pri[j]] % MOD; } } return pri; } void dfs_enum(vector<pii>&fac, int p, int d, vec&res) { if (d == (int)fac.size()) { res.pb(p); return ; } int v = fac[d].first, t = fac[d].second, c = 1; dfs_enum(fac, p, d + 1, res); for (int i = 0; i < t; ++i) { c = c * v; dfs_enum(fac, p * c, d + 1, res); } } vec enumerate(vector<pii>&fac) { vec res; dfs_enum(fac, 1, 0, res); return res; } vec factorize(LL val) { vec isPrime; vector<pii> fac; vec pri = getPrime(isPrime); for (int i = 0; i < (int)pri.size(); ++i) { int p = pri[i]; if (val % p == 0) { fac.pb(mp(p, 0)); while (val % p == 0) { val /= p; ++fac.back().second; } } } if (val != 1) fac.pb(mp(val, 1)); return enumerate(fac); } int getPrimeRoot(LL val) { int pr; vec f = factorize(val - 1); for (pr = 2; ; ++pr) { if (fpw((LL)pr, val - 1LL, (LL)MOD) == 1) { bool ok = true; for (int i = 0; i < (int)f.size(); ++i) if (f[i] != (val - 1) && fpw((LL)pr, (LL)f[i], (LL)MOD) == 1) ok = false; if (ok) return pr; } } } int GN[24], rGN[24]; int getGN(int m, int r) { if (r == 1) { if (GN[m] != 0) return GN[m]; return GN[m] = fpw(3LL, (MOD-1LL) / (1<<m), (LL)MOD); } else { if (rGN[m] != 0) return rGN[m]; return rGN[m] = fpw((LL)GN[m], MOD-2LL, (LL)MOD); } } int b[MAXN]; void dft(int *a, int m, int r) { if (m == 0) return ; int N = 1<<m; memcpy(b, a, (sizeof a[0]) * N); for (int i = 0; i < (N>>1); ++i) a[i] = b[i<<1], a[(N>>1) + i] = b[(i<<1)|1]; dft(a, m - 1, r), dft(a + (N>>1), m - 1, r); int gn = getGN(m, r), c = 1; for (int i = 0; i < (N>>1); c = 1LL * c * gn % MOD, ++i) { b[i] = (MOD + (a[i] + 1LL * c * a[i + (N>>1)] % MOD) % MOD) % MOD; b[i + (N>>1)] = (MOD + (a[i] - 1LL * c * a[i + (N>>1)] % MOD) % MOD) % MOD; } memcpy(a, b, (sizeof a[0]) * N); } }; using namespace NTT; int j2[MAXN], fac[MAXN], ifac[MAXN], ta[MAXN], tb[MAXN], f[MAXN]; void calc(int l, int r) { if (l == r) return; int m = (l + r) >> 1; calc(l, m); int len = r - l + 1, t = 0; for (; (1<<t) < len; ++t); for (int i = l; i <= m; ++i) ta[i - l] = f[i] * 1LL * ifac[i] % MOD; for (int i = m + 1; i < m + (1<<t); ++i) ta[i - l] = 0; for (int i = 0; i < (1<<t); ++i) tb[i] = j2[i] % MOD; dft(ta, t, 1); dft(tb, t, 1); for (int i = 0; i < (1<<t); ++i) ta[i] = ta[i] * 1LL * tb[i] % MOD; dft(ta, t, -1); for (int i = m + 1; i <= r; ++i) (f[i] += 1LL * fac[i - 1] * ta[i - l] % MOD * inv[1<<t] % MOD) %= MOD; calc(m + 1, r); } int main() { #ifdef lol freopen("G.in", "r", stdin); freopen("G.out", "w", stdout); #endif getPrimeRoot(MOD); fac[0] = 1; j2[0] = 0; for (int i = 1; i < MAXN; ++i) { fac[i] = fac[i-1] * 1LL * i % MOD; j2[i] = i * 1LL * i % MOD; } ifac[MAXN-1] = fpw((LL)fac[MAXN-1], MOD - 2LL, (LL)MOD); for (int i = MAXN-2; 0 <= i; --i) ifac[i] = (i + 1LL) * ifac[i + 1] % MOD; f[0] = 1; calc(0, 100000); int x; while (scanf("%d", &x) != EOF) wt(f[x]); return 0; }
时间: 2024-10-24 08:22:05