[luogu5162]WD与积木

设$g_{n}$表示$n$个积木放的方案数,枚举最后一层所放的积木,则有$g_{n}=\sum_{i=1}^{n}c(n,i)g_{n-i}$(因为积木有编号的所以要选出$i$个)

将组合数展开并化简,得到$\frac{g_{n}}{n!}=\sum_{i=1}^{n}\frac{g_{n-i}}{i!(n-i)!}$,明显是一个分治fft的形式,转换为多项式求逆:

令$g_{n}$的指数生成函数为$G(x)=\sum_{i=0}^{\infty}\frac{g_{i}}{i!}x^{i}$,再令$H(x)=\sum_{i=0}^{\infty}\frac{x^{i}}{i!}$,考虑$H(x)G(x)$,代入并将$i=0$和$j=0$提出可得$H(x)G(x)=\sum_{i=0}^{\infty}(\sum_{j=0}^{i}H(x)[j]\cdot G(x)[i-j])x^{i}=2G(x)-1$,即$G(x)=\frac{1}{2-H(x)}$

设$f_{n}$表示$n$个积木放的方案数的层数之和,那么根据期望的定义,答案$E=\frac{f_{n}}{g_{n}}$

类似的,可以写出$f_{n}$的递推式,即$f_{n}=g_{n}+\sum_{i=1}^{n}c(n,i)f_{n-i}$($g_{n}$是因为每一个方案都要+1),将$g_{n}$的表达式展开,有$\frac{f_{n}}{n!}=\sum_{i=1}^{n}\frac{f_{n-i}+g_{n-i}}{i!(n-i)!}$,同样去转换为多项式求逆:

令$f_{n}$的指数生成函数为$F(x)=\sum_{i=0}^{\infty}\frac{f_{i}}{i!}x^{i}$,$H(x)$和$G(x)$相同,考虑$H(x)(G(x)+F(x))$,类似上面可得$H(x)(G(x)+F(x))=G(x)+2F(x)$(注意$f_{0}=0$),即$F(x)=\frac{(H(x)-1)G(x)}{2-H(x)}=(H(x)-1)G(x)^{2}$

最终答案即$\frac{F(x)[n]}{G(x)[n]}$(都除以了$n!$),注意最后一步不能将$\frac{F(x)}{G(x)}$作为结果,因为这不等于答案

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N (1<<18)
 4 #define mod 998244353
 5 int t,n,a[N],c[N],h[N],g[N],f[N];
 6 int ksm(int n,int m){
 7     if (!m)return 1;
 8     int s=ksm(n,m>>1);
 9     s=1LL*s*s%mod;
10     if (m&1)s=1LL*s*n%mod;
11     return s;
12 }
13 void ntt(int *a,int n,int p){
14     for(int i=0;i<(1<<n);i++){
15         int rev=0;
16         for(int j=0;j<n;j++)rev=rev*2+((i&(1<<j))>0);
17         if (i<rev)swap(a[i],a[rev]);
18     }
19     for(int i=2;i<=(1<<n);i*=2){
20         int s=ksm(3,(mod-1)/i);
21         if (p)s=ksm(s,mod-2);
22         for(int j=0;j<(1<<n);j+=i)
23             for(int k=0,ss=1;k<(i>>1);k++,ss=1LL*ss*s%mod){
24                 int x=a[j+k],y=1LL*a[j+k+(i>>1)]*ss%mod;
25                 a[j+k]=(x+y)%mod;
26                 a[j+k+(i>>1)]=(x+mod-y)%mod;
27             }
28     }
29     if (p){
30         int s=ksm((1<<n),mod-2);
31         for(int i=0;i<(1<<n);i++)a[i]=1LL*a[i]*s%mod;
32     }
33 }
34 void Inv(int *a,int *b,int n){
35     if (!n){
36         b[0]=ksm(a[0],mod-2);
37         return;
38     }
39     Inv(a,b,n-1);
40     for(int i=0;i<(1<<n);i++)c[i]=a[i];
41     for(int i=(1<<n);i<(1<<n+1);i++)c[i]=0;
42     ntt(c,n+1,0);
43     ntt(b,n+1,0);
44     for(int i=0;i<(1<<n+1);i++)b[i]=1LL*b[i]*(mod+2-1LL*c[i]*b[i]%mod)%mod;
45     ntt(b,n+1,1);
46     for(int i=(1<<n);i<(1<<n+1);i++)b[i]=0;
47 }
48 int main(){
49     a[0]=1;
50     for(int i=1;i<N;i++)a[i]=1LL*a[i-1]*ksm(i,mod-2)%mod;
51     h[0]=(mod+2-a[0])%mod;
52     for(int i=1;i<N/2;i++)h[i]=(mod-a[i])%mod;
53     Inv(h,g,17);
54     memcpy(f,g,sizeof(g));
55     ntt(f,18,0);
56     for(int i=0;i<N;i++)f[i]=1LL*f[i]*f[i]%mod;
57     ntt(f,18,1);
58     for(int i=N/2;i<N;i++)f[i]=0;
59     ntt(f,18,0);
60     h[0]=0;
61     for(int i=1;i<N/2;i++)h[i]=a[i];
62     ntt(h,18,0);
63     for(int i=0;i<N;i++)f[i]=1LL*f[i]*h[i]%mod;
64     ntt(f,18,1);
65     scanf("%d",&t);
66     while (t--){
67         scanf("%d",&n);
68         printf("%lld\n",1LL*f[n]*ksm(g[n],mod-2)%mod);
69     }
70 }
View Code

 

posted @ 2020-10-22 16:27  PYWBKTDA  阅读(159)  评论(0编辑  收藏  举报