传送门

题解

比赛的时候光顾着算某一个\(n\)的答案是多少忘了考虑不同的\(n\)之间的联系了……而且我也很想知道为什么推着推着会变成一个二项式反演……

设\(f_n\)为\(n\)块积木时的总的层数,\(g_n\)为\(n\)块积木时总的方案数,则有$$g_n=\sum_{i=1}^n\binom{n}{i}g_{n-i}$$

\[f_n=g_n+\sum_{i=1}^n\binom{n}{i}f_{n-i}
\]

\(g\)的话就是枚举第一层有哪几个,\(f\)的话也是枚举第一层有几个,前面的\(g_n\)是第一层贡献的总高度,边界条件为\(g_0=1,f_0=0\)(\(g_0\)的话……因为空集也算一个方案吧……大概……)

然后按照惯例构造指数级生成函数$$F(x)=\sum_{i=0}{\infty}\frac{f_i}{i!}xi,G(x)=\sum_{i=0}{\infty}\frac{g_i}{i!}xi,H(x)=\sum_{i=0}{\infty}\frac{xi}{i!}$$

于是上面两个式子就可以写成卷积的形式,注意上面的下标是从\(1\)开始的,所以卷的时候要多一个$$2G=HG+1,2F=G+HG-1$$

常数项感性理解吧我实在不知道怎么解释……或者该说是把多项式的常数项代入计算为使等式成立所以常数项是这个?

于是解方程可得$$G=\frac{1}{2-H},F=G(G-1)$$

然后到隔壁把多项式的板子抄来就好了

\(NTT\)板子打错我觉得自己也是挺光荣的……

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=5e5+5,P=998244353,Gi=332748118;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
int A[N],B[N],r[N],O[N],F[N],G[N],H[N],D[N],fac[N],inv[N];
int n,m,len;
void init(){
fac[0]=inv[0]=fac[1]=inv[1]=1;
fp(i,2,n)fac[i]=mul(fac[i-1],i);
inv[n]=ksm(fac[n],P-2);
fd(i,n-1,1)inv[i]=mul(inv[i+1],i+1);
}
void NTT(int *A,int ty,int len){
int lim=1,l=0;while(lim<len)lim<<=1,++l;
fp(i,0,lim-1)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
fp(i,0,lim-1)if(i<r[i])swap(A[i],A[r[i]]);
for(R int mid=1;mid<lim;mid<<=1){
R int I=(mid<<1),Wn=ksm(ty==1?3:Gi,(P-1)/I);O[0]=1;
fp(i,1,mid-1)O[i]=mul(O[i-1],Wn);
for(R int j=0;j<lim;j+=I)for(R int k=0;k<mid;++k){
int x=A[j+k],y=mul(A[j+k+mid],O[k]);
A[j+k]=add(x,y),A[j+k+mid]=dec(x,y);
}
}if(ty==-1)for(R int i=0,inv=ksm(lim,P-2);i<lim;++i)A[i]=mul(A[i],inv);
}
void Inv(int *a,int *b,int len){
if(len==1)return (void)(b[0]=ksm(a[0],P-2));
Inv(a,b,len>>1);fp(i,0,len-1)A[i]=a[i],B[i]=b[i];
NTT(A,1,len<<1),NTT(B,1,len<<1);
fp(i,0,(len<<1)-1)A[i]=mul(A[i],mul(B[i],B[i]));
NTT(A,-1,len<<1);
fp(i,0,len-1)b[i]=dec(mul(b[i],2),A[i]);
}
int main(){
// freopen("testdata.in","r",stdin);
int T=read();n=1e5,init();
H[0]=1;fp(i,1,n)H[i]=P-inv[i];
len=1;while(len<=n)len<<=1;Inv(H,G,len);
fp(i,0,len-1)D[i]=mul(G[i],fac[i]),H[i]=G[i];
--H[0];NTT(G,1,len<<1),NTT(H,1,len<<1);
fp(i,0,(len<<1)-1)G[i]=mul(G[i],H[i]);
NTT(G,-1,len<<1);
fp(i,0,n)G[i]=mul(ksm(D[i],P-2),mul(G[i],fac[i]));
while(T--)n=read(),print(G[n]);
return Ot(),0;
}

P5162 WD与积木(多项式求逆+生成函数)的更多相关文章

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

    不要以为用上Stirling数就一定离正解更近,FFT都是从DP式本身出发的. 设f[i]为i个积木的所有方案的层数总和,g[i]为i个积木的方案数,则答案为$\frac{f[i]}{g[i]}$ 转 ...

  2. BZOJ1042 HAOI2008硬币购物(任意模数NTT+多项式求逆+生成函数/容斥原理+动态规划)

    第一眼生成函数.四个等比数列形式的多项式相乘,可以化成四个分式.其中分母部分是固定的,可以多项式求逆预处理出来.而分子部分由于项数很少,询问时2^4算一下贡献就好了.这个思路比较直观.只是常数巨大,以 ...

  3. BZOJ 3625:小朋友和二叉树 多项式开根+多项式求逆+生成函数

    生成函数这个东西太好用了~ code: #include <bits/stdc++.h> #define ll long long #define setIO(s) freopen(s&q ...

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

    显然的做法是求出斯特林数,但没有什么优化空间. 考虑一种暴力dp,即设f[i]为i块积木的所有方案层数之和,g[i]为i块积木的方案数.转移时枚举第一层是哪些积木,于是有f[i]=g[i]+ΣC(i, ...

  5. 洛谷 P5162 WD与积木【多项式求逆】

    设f[i]为i个积木能堆出来的种类,g[i]为i个积木能堆出来的种类和 \[ f[n]=\sum_{i=1}^{n}C_{n}^{i}g[n-i] \] \[ g[n]=\sum_{i=1}^{n}C ...

  6. LOJ2527 HAOI2018 染色 容斥、生成函数、多项式求逆

    传送门 调了1h竟然是因为1004535809写成了998244353 "恰好有\(K\)种颜色出现了\(S\)次"的限制似乎并不容易达到,考虑容斥计算. 令\(c_j\)表示强制 ...

  7. 【XSY2612】Comb Avoiding Trees 生成函数 多项式求逆 矩阵快速幂

    题目大意 本题的满二叉树定义为:不存在只有一个儿子的节点的二叉树. 定义一棵满二叉树\(A\)包含满二叉树\(B\)当且经当\(A\)可以通过下列三种操作变成\(B\): 把一个节点的两个儿子同时删掉 ...

  8. 2019.01.01 bzoj3625:小朋友和二叉树(生成函数+多项式求逆+多项式开方)

    传送门 codeforces传送门codeforces传送门codeforces传送门 生成函数好题. 卡场差评至今未过 题意简述:nnn个点的二叉树,每个点的权值KaTeX parse error: ...

  9. 【BZOJ3625】【codeforces438E】小朋友和二叉树 生成函数+多项式求逆+多项式开根

    首先,我们构造一个函数$G(x)$,若存在$k∈C$,则$[x^k]G(x)=1$. 不妨设$F(x)$为最终答案的生成函数,则$[x^n]F(x)$即为权值为$n$的神犇二叉树个数. 不难推导出,$ ...

随机推荐

  1. 【试水CAS-4.0.3】第06节_CAS服务端配置HTTPS

    完整版见https://jadyer.github.io/2012/05/30/tomcat-https/ /** * @see CAS服务端配置HTTPS * @see -------------- ...

  2. Ubuntu下编译Android JNI实例全过程

    第一步:保证make和gcc可用 在shell中输入make-v.不报错就是对的.(可參考http://wenku.baidu.com/view/d87586c24028915f804dc24a.ht ...

  3. 通达OA 一些工作流调整后带来的后果及应对措施

    近期单位有个工作流须要改动,原因是最早设计时控件的字段设计不规范,控件直接使用了人员的名字来命名了.这不使用手机訪问时就出问题了,名字会直接显示出来,如今就须要进行调整. 调整初步有两个方案: 一是全 ...

  4. Page Design for Sexable Forum

    Design Demo 1. Home of Sexable Forum 1.1  home page not logined. 1,2 home page logined. 2. Pages wit ...

  5. strsep strpbrk

    #include <stdio.h> #include <string.h> int main(void) { char s[] = "aa,bb,cc.11,22, ...

  6. html-基本form元素---ShinePans

    <html> <meta http-equiv="content-type" content="text/html;charset=UTF-8" ...

  7. UIPanGestureRecognizer上下左右滑动方向推断算法

    CGFloat const gestureMinimumTranslation = 20.0; typedef enum :NSInteger { kCameraMoveDirectionNone, ...

  8. exists用在linq上

    SQL里面,有时候会用到exists或者not exists. select * from yb t1 where not exists(select 1 from yb t2 where trunc ...

  9. To verify Hadoop releases using GPG

    To verify Hadoop releases using GPG http://hadoop.apache.org/releases.html To verify Hadoop releases ...

  10. acd - 1427 - Nice Sequence(线段树)

    题意:一个由n个数组成的序列(序列元素的范围是[0, n]).求最长前缀 j .使得在这个前缀 j 中对于随意的数 i1 < i2.都满足随意的 m <= j.i1 在前 m 个数里出现的 ...