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 }
nowcoder 272 F. Friendly Polynomial

posted @ 2018-12-13 19:32 KingSann 阅读(...) 评论(...) 编辑 收藏