[Luogu5162]WD与积木(多项式求逆)

不要以为用上Stirling数就一定离正解更近,FFT都是从DP式本身出发的。

设f[i]为i个积木的所有方案的层数总和,g[i]为i个积木的方案数,则答案为$\frac{f[i]}{g[i]}$

转移枚举第一层是哪些积木:$$f_n=g_n+\sum_{i=1}^{n}\binom{n}{i}f_{n-i},f_0=0$$$$g_n=\sum_{i=1}^{n}\binom{n}{i}g_{n-i},g_0=1$$

转化成卷积形式:$$\frac{f_n}{n!}=\frac{g_n}{n!}+\sum_{i=1}^{n}\frac{1}{i!}\times \frac{f_{n-i}}{i!}$$$$\frac{g_n}{n!}=\sum_{i=1}^{n}\frac{1}{i!}\times \frac{g_{n-i}}{(n-i)!}$$

构造生成函数:$F(x)=\sum\frac{f_i}{i!}x^i$,$G(x)=\sum\frac{g_i}{i!}x^i$,$H(x)=\sum\frac{x^i}{i!}$。

则根据上式有:$F(x)=G(x)+F(x)(H(x)-1)-1$,$G(x)=G(x)(H(x)-1)+1$。

移项得:$F(x)=\frac{G(x)-1}{2-H(x)}=G(x)(G(x)-1)$,$G(x)=\frac{1}{2-H(x)}$。

多项式求逆即可。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 using namespace std;
 5
 6 const int N=500010,mod=998244353;
 7 int n,m,T,fac[N],h[N],g[N],f[N],inv[N],rev[N],tmp[N];
 8
 9 int ksm(int a,int b){
10     int res=1;
11     for (; b; a=1ll*a*a%mod,b>>=1)
12         if (b & 1) res=1ll*res*a%mod;
13     return res;
14 }
15
16 void DFT(int a[],int n,bool f){
17     for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
18     for (int i=1; i<n; i<<=1){
19         int wn=ksm(3,f ? (mod-1)/(i<<1) : (mod-1)-(mod-1)/(i<<1));
20         for (int p=i<<1,j=0; j<n; j+=p){
21             int w=1;
22             for (int k=0; k<i; k++,w=1ll*w*wn%mod){
23                 int x=a[j+k],y=1ll*w*a[i+j+k]%mod;
24                 a[j+k]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
25             }
26         }
27     }
28     if (f) return;
29     int inv=ksm(n,mod-2);
30     for (int i=0; i<n; i++) a[i]=1ll*a[i]*inv%mod;
31 }
32
33 void Inv(int a[],int b[],int l){
34     if (l==1){ b[0]=ksm(a[0],mod-2); return; }
35     Inv(a,b,l>>1); int n=1,L=0;
36     for (; n<=l; n<<=1) L++;
37     for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
38     for (int i=0; i<l; i++) tmp[i]=a[i],tmp[i+l]=0;
39     DFT(tmp,n,1); DFT(b,n,1);
40     for (int i=0; i<n; i++) tmp[i]=1ll*b[i]*(2-1ll*tmp[i]*b[i]%mod+mod)%mod;
41     DFT(tmp,n,0);
42     for (int i=0; i<l; i++) b[i]=tmp[i],b[i+l]=0;
43 }
44
45 int main(){
46     n=100000;
47     fac[0]=1; rep(i,1,n) fac[i]=1ll*fac[i-1]*i%mod;
48     inv[n]=ksm(fac[n],mod-2);
49     for (int i=n-1; ~i; i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
50     rep(i,1,n) h[i]=mod-inv[i]; h[0]=1;
51     for (m=1; m<=n; m<<=1); Inv(h,g,m);
52     for (int i=1; i<m; i++) f[i]=g[i];
53     f[0]=(g[0]-1+mod)%mod; m<<=1;
54     DFT(f,m,1); DFT(g,m,1);
55     for (int i=0; i<m; i++) f[i]=1ll*f[i]*g[i]%mod;
56     DFT(f,m,0); DFT(g,m,0);
57     for (scanf("%d",&T); T--; ) scanf("%d",&n),printf("%lld\n",1ll*f[n]*ksm(g[n],mod-2)%mod);
58     return 0;
59 }

原文地址:https://www.cnblogs.com/HocRiser/p/10227080.html

时间: 2024-08-30 15:35:44

[Luogu5162]WD与积木(多项式求逆)的相关文章

Luogu5162 WD与积木(生成函数+多项式求逆)

显然的做法是求出斯特林数,但没有什么优化空间. 考虑一种暴力dp,即设f[i]为i块积木的所有方案层数之和,g[i]为i块积木的方案数.转移时枚举第一层是哪些积木,于是有f[i]=g[i]+ΣC(i,j)·f[i-j],g[i]=ΣC(i,j)·g[i-j] (j=1~i). 考虑优化 .我们发现这个转移非常像卷积.写成卷积形式,有f[i]=g[i]+Σi!·Σf[i-j]/j!/(i-j)!,g[i]=i!·Σg[i-j]/j!/(i-j)!.直接分治NTT即可. 诶是不是强行多了个log?考

NTT+多项式求逆+多项式开方(BZOJ3625)

定义多项式h(x)的每一项系数hi,为i在c[1]~c[n]中的出现次数. 定义多项式f(x)的每一项系数fi,为权值为i的方案数. 通过简单的分析我们可以发现:f(x)=2/(sqrt(1-4h(x))+1) 于是我们需要多项式开方和多项式求逆. 多项式求逆: 求B(x),使得A(x)*B(x)=1 (mod x^m) 考虑倍增. 假设我们已知A(x)*B(x)=1 (mod x^m),要求C(x),使得A(x)*C(x)=1 (mod x^(2m)) 简单分析可得C(x)=B(x)*(2-A

【BZOJ 3456】 3456: 城市规划 (NTT+多项式求逆)

3456: 城市规划 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 658  Solved: 364 Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一

多项式求逆 学习总结

感觉蒟蒻现在学多项式求逆貌似有些晚了 不过真的很有意思了(然而省选的时候自己还在玩泥巴什么也不会 多项式求逆是基于倍增的 假设我们知道 h(x)f(x)=1(mod x^n) 移项得 (h(x)*f(x)-1)=0(mod x^n) 两边同时求平方得 h(x)^2*f(x)^2 - 2*h(x)*f(x) +1 = 0 (mod x^2n) 设g(x)*f(x)=1(mod x^2n) 两边同时乘以g(x)可以得 h(x)^2*f(x) -2*h(x) + g(x) =0 (mod x^2n)

Nescafe41 ProblemA 异化多肽 多项式求逆

题目大意:. 思路: 搞出C的生成函数F(x),那么: 长度为1的答案为F(x) 长度为2的答案为F2(x) - 故最终的答案为 F(x)+F2(x)+F3(x)+... =1?F+∞(x)1?F(x) =11?F(x) 然后就是多项式求逆了= = 跪picks大毒瘤 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M (263000&

【BZOJ】4555: [Tjoi2016&amp;Heoi2016]求和 排列组合+多项式求逆 或 斯特林数+NTT

[题意]给定n,求Σi=0~nΣj=1~i s(i,j)*2^j*j!,n<=10^5. [算法]生成函数+排列组合+多项式求逆 [题解]参考: [BZOJ4555][Tjoi2016&Heoi2016]求和-NTT-多项式求逆 $ans=\sum_{i=0}^{n}\sum_{j=0}^{i}s(i,j)*2^j*j!$ 令$g(n)=\sum_{j=0}^{n}s(n,j)*2^j*j!$ 则ans是Σg(i),只要计算出g(i)的生成函数就可以统计答案. g(n)可以理解为将n个数划分

【bzoj3456】城市规划 容斥原理+NTT+多项式求逆

题目描述 求出n个点的简单(无重边无自环)无向连通图数目mod 1004535809(479 * 2 ^ 21 + 1). 输入 仅一行一个整数n(<=130000) 输出 仅一行一个整数, 为方案数 mod 1004535809. 样例输入 3 样例输出 4 题解 容斥原理+NTT+多项式求逆 设 $f_i$ 表示 $i$ 个点的简单无向连通图的数目,$g_i$ 表示 $i$ 个点的简单无向图的数目. 根据定义得 $g_i=2^{\frac{n(n-1}2}$ . 对于 $f_i$ ,考虑容斥

多项式求逆

多项式求逆 求 \(A(x)\) 在 \(\%x^{n}\) 意义下的逆元 \(B(x)\) 首先求出 \(A(x)\) 在 \(\%x^{\lceil \frac{n}{2} \rceil}\) 意义下的逆元 \(C(x)\),即 $A(x)C(x)=1 $ \((\%x^{\lceil \frac{n}{2} \rceil})\) 移项得 \(A(x)C(x)-1 = 0\) \((\%x^{\lceil \frac{n}{2} \rceil})\) 两边平方 \(A^{2}(x)C^{2}

[Codeforces438E][bzoj3625] 小朋友和二叉树 [多项式求逆+多项式开根]

题面 传送门 思路 首先,我们把这个输入的点的生成函数搞出来: \(C=\sum_{i=0}^{lim}s_ix^i\) 其中\(lim\)为集合里面出现过的最大的数,\(s_i\)表示大小为\(i\)的数是否出现过 我们再设另外一个函数\(F\),定义\(F_k\)表示总权值为\(k\)的二叉树个数 那么,一个二叉树显然可以通过两个子树(可以权值为0,也就是空子树)和一个节点构成 那么有如下求\(F\)的式子 \(F_0=1\) \(F_k=\sum_{i=0}^k s_i \sum_{j=0