nowcoder 272 F. Friendly Polynomial
设一个长度为 $n$ 的排列是合法的,当且仅当 $\exists i \in [1,n-1]$,使得 $a_1, a_2, \cdots , a_i$ 恰好构成一个 $1 \sim i$ 的排列
分别求出长度为 $1 \sim n$ 的合法排列数
输出对 $998244353$ 取模
$3 \le n \le 10^5$
大概就是多项式理论那一类的吧……
设 $f_n$ 表示长度为 $n$ 的合法排列数
计数的时候只在一个最大的 $i$ 处计数,即只在 $a_1 \sim a_i$ 是个排列,且 $a_{i+1} \sim a_{n}$ 不是个排列的时候进行计数
显然有:
$$
f_n=\sum_{i=1}^{n-1}i!\left((n-i)!-f_{n-i}\right)
$$
$i!$ 表示强行钦定 $i$ 是最大的可行的,然后剩余的 $n-i$ 个位置一定是不可行的,即总方案减去合法方案
考虑如何计算这个式子:
$$
\begin{aligned}
f_n
=&\sum_{i=1}^{n-1}i!\left((n-i)!-f_{n-i}\right) \\
=&\left(\sum_{i=1}^{n-1}i!(n-i)!\right)-\left(\sum_{i=1}^{n-1}i!f_{n-i}\right) \\
\end{aligned}
$$
发现这里还不好搞事情……或者说用分治 $FFT$ 似乎也可以……
不妨钦定 $0!=0$,这样就方便搞事情了,上面那个式子就相当于:
$$
f_n=\left(\sum_{i=0}^{n}i!(n-i)!\right)-\left(\sum_{i=0}^{n}i!f_{n-i}\right) \\
$$
这个是啥?设 $g(n)=n!$,也就是说:
$$
f=g^2-g \times f
$$
化简一下就是:
$$
f=\frac{g^2}{1+g}
$$
然后由于 $g$ 是已知的,于是只需要去搞一个多项式求逆的板子就行了
1 #include "bits/stdc++.h" 2 using namespace std; 3 typedef long long ll; 4 const int N = 4e6 + 10; 5 const ll p = 998244353; 6 const ll g[2] = { 3, (p + 1) / 3}; 7 ll a[N], b[N], f[N]; int n, m; 8 ll pw(ll a, ll b) { 9 ll r = 1; 10 for( ; b ; b >>= 1, a = a * a % p) if(b & 1) r = r * a % p; 11 return r; 12 } 13 ll inv(ll x) { 14 return pw(x, p - 2); 15 } 16 int rev(int x, int n) { 17 int r = 0; 18 for(int i = 0 ; (1 << i) < n ; ++ i) r = (r << 1) | ((x >> i) & 1); 19 return r; 20 } 21 void ntt(ll *a, int n, int t) { 22 for(int i = 0 ; i < n ; ++ i) f[rev(i, n)] = a[i]; 23 for(int i = 2 ; i <= n ; i <<= 1) { 24 ll wn = pw(g[t], (p - 1) / i); 25 for(int j = 0 ; j < n ; j += i) { 26 ll w = 1; 27 for(int k = j ; k < j + i / 2 ; ++ k) { 28 ll u = f[k], v = w * f[k + i / 2] % p; 29 f[k] = (u + v) % p, f[k + i / 2] = ((u - v) % p + p) % p; 30 w = w * wn % p; 31 } 32 } 33 } 34 for(int i = 0 ; i < n ; ++ i) { 35 a[i] = f[i] % p; 36 if(t) a[i] = a[i] * inv(n) % p; 37 } 38 } 39 40 ll t[N], aa[N], h[N]; 41 42 void sol(int n) { 43 if(n == 1) { 44 b[0] = inv(a[0]); 45 } else { 46 sol((n + 1) / 2); 47 for(int i = 0 ; i < n ; ++ i) t[i] = 2 * b[i] % p, aa[i] = a[i]; 48 int len = 1; while(len <= 2 * n) len <<= 1; 49 for(int i = n ; i <= len ; ++ i) aa[i] = 0; 50 ntt(aa, len, 0), ntt(b, len, 0); 51 for(int i = 0 ; i < len ; ++ i) h[i] = aa[i] * b[i] % p * b[i] % p; 52 ntt(h, len, 1); 53 for(int i = 0 ; i < n ; ++ i) b[i] = ((t[i] - h[i]) % p + p) % p; 54 for(int i = n ; i < len ; ++ i) b[i] = 0; 55 } 56 } 57 58 ll poi[N], fac[N]; 59 const int mod = p; 60 61 void init(int n) { 62 fac[1] = 1; 63 for(int i = 2 ; i <= n ; ++ i) fac[i] = fac[i - 1] * i % mod; 64 65 const int len = 2 * 262144; 66 for(int i = 0 ; i <= n ; ++ i) { 67 a[i] = fac[i]; 68 } 69 a[0] ++; 70 sol(n); 71 a[0] --; 72 ntt(a, len, 0); 73 ntt(b, len, 0); 74 for(int i = 0 ; i < len ; ++ i) a[i] = a[i] * a[i] % mod * b[i] % mod; 75 ntt(a, len, 1); 76 } 77 78 int main() { 79 init(1e5); 80 int t; scanf("%d", &t); 81 while(t --) { 82 int x; scanf("%d", &x); 83 printf("%lld\n", (a[x] + mod) % mod); 84 } 85 }