981 words
5 minutes
多项式
板子
#include<bits/stdc++.h>#define ll long long#define ld double#define N 3000500#define mod 998244353const ld PI=acos(-1.0);using std::string;string s1,s2;int read(){int p=0,flg=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') flg=-1;c=getchar();}while(c>='0'&&c<='9'){p=p*10+c-'0';c=getchar();}return p*flg;}void write(int x){if (!x)return;write(x/10);putchar(x%10+'0');}namespace Poly { int p[N],q[N],r[N],w[N],invnum[N],invfac[N],fac[N]; int add(int x,int y){return x+y>mod?x+y-mod:x+y;} int dec(int x,int y){return x-y<0?x-y+mod:x-y;} int ext(int n){return n==1?1:(1<<(std::__lg(n-1)+1));} int qpow(int a,int b){int res=1;for (;b;b>>=1,a=1ll*a*a%mod)if (b&1)res=1ll*res*a%mod;return res;} void get_r(int n){for (int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|(i&1?n>>1:0);} void print(int *a,int n){for (int i=0;i<n;i++)printf("%d%c",a[i]," \n"[i==n-1]);} void init_poly(){ for(int k=2,m=1;k<=N;k<<=1,m<<=1){ w[m]=1; for(int i=m+1,x=qpow(3,(mod-1)/k);i<k;i++) w[i]=1ll*w[i-1]*x%mod; }invnum[1]=1; for (int i=2;i<N;i++)invnum[i]=1ll*(mod-mod/i)*invnum[mod%i]%mod; invfac[0]=1; for (int i=1;i<N;i++)invfac[i]=1ll*invfac[i-1]*invnum[i]%mod; fac[0]=1; for (int i=1;i<N;i++)fac[i]=1ll*fac[i-1]*i%mod; } void NTT(int *a,int n,int op){ for (int i=0;i<n;i++)if (i<r[i])std::swap(a[i],a[r[i]]); for (int k=2,m=1;k<=n;m<<=1,k<<=1){ for (int i=0;i<n;i+=k) for (int j=i,*x=w+m;j<i+m;x++,j++){ int v=1ll*a[j+m]*(*x)%mod; a[j+m]=dec(a[j],v);a[j]=add(a[j],v); } } if (op==-1){ std::reverse(a+1,a+n); for (int i=0,v=qpow(n,mod-2);i<n;i++)a[i]=1ll*a[i]*v%mod; } } void mul(int *a,int *b,int n,int m){ if (!n||!m)return; int len=ext(n+m-1); for (int i=0;i<len;i++)p[i]=i<n?a[i]:0,q[i]=i<m?b[i]:0; get_r(len); NTT(p,len,1);NTT(q,len,1); for (int i=0;i<len;i++)a[i]=1ll*p[i]*q[i]%mod; NTT(a,len,-1); } void mul_2(int *a,int *b,int *c,int n,int m){ if (!n||!m)return; int len=ext(n+m-1); for (int i=0;i<len;i++)p[i]=i<n?a[i]:0,q[i]=i<m?b[i]:0; get_r(len); NTT(p,len,1);NTT(q,len,1); for (int i=0;i<len;i++)c[i]=1ll*p[i]*q[i]%mod; NTT(c,len,-1); } void _inv(int *a,int *b,int n){ static int c[N],d[N]; n=ext(n);memset(b,0,4*n);b[0]=qpow(a[0],mod-2); for (int k=2;k<=n;k<<=1){ for (int i=0;i<k<<1;i++)c[i]=i<k?a[i]:0,d[i]=i<k>>1?b[i]:0; get_r(k);NTT(d,k,1); for (int i=0;i<k;i++)d[i]=1ll*d[i]*d[i]%mod; NTT(d,k,-1);get_r(k<<1);NTT(c,k<<1,1);NTT(d,k<<1,1); for (int i=0;i<k<<1;i++)c[i]=1ll*c[i]*d[i]%mod; NTT(c,k<<1,-1); for (int i=0;i<k;i++)b[i]=(2ll*b[i]-c[i]+mod)%mod; } } void _diff(int *a,int *b,int n){//a-n个数 for (int i=1;i<n;i++)b[i-1]=1ll*i*a[i]%mod;b[n-1]=0; } void _integ(int *a,int *b,int n){//b-n个数 for (int i=1;i<n;i++)b[i]=1ll*invnum[i]*a[i-1]%mod;b[0]=0; } void _ln(int *a,int *b,int n){ static int c[N],d[N]; assert(a[0]==1); n=ext(n); _inv(a,c,n),_diff(a,d,n),mul(c,d,n,n);_integ(c,b,n); } void _exp(int *a,int *b,int n){ static int c[N]; assert(a[0]==0); n=ext(n);memset(b,0,4*n);memset(c,0,4*n);b[0]=1; for (int k=2;k<=n;k<<=1){ _ln(b,c,k); for (int i=0;i<k;i++)c[i]=dec(a[i],c[i]); c[0]++;mul(b,c,k,k);
} } void _sqrt(int *a,int *b,int n){ static int c[N],d[N]; static const int inv2=(mod+1)>>1; assert(a[0]==1); n=ext(n);memset(b,0,4*n);b[0]=1; for (int k=2;k<=n;k<<=1){ memcpy(c,a,4*k);_inv(b,d,k),mul(c,d,k,k); for (int i=0;i<k;i++)b[i]=1ll*(b[i]+c[i])*inv2%mod; } } void _pow(int *a,int *b,int n,string k){ static int c[N],d[N]; int u=0,k1=0,k2=0; memset(b,0,4*n); for (int i=0;i<k.size();i++)k1=(10ll*k1+k[i]-'0')%mod,k2=(10ll*k2+k[i]-'0')%(mod-1); for (u=0;u<n&&!a[u];u++); if ((u&&k.size()>=5)||1ll*u*k1>=n)return; for (int i=u,x=qpow(a[u],mod-2);i<n;i++)c[i-u]=1ll*a[i]*x%mod; _ln(c,d,n-u); for (int i=0;i<n-u;i++)d[i]=1ll*d[i]*k1%mod; _exp(d,c,n-u); for (int i=u*k1,x=qpow(a[u],k2);i<n;i++)b[i]=1ll*c[i-u*k1]*x%mod; } void _pow_p(int *a,int *b,int n,string k){ static int c[N],d[N]; int u=0,k1=0,k2=0; for (int i=0;i<k.size();i++)k1=(10ll*k1+k[i]-'0')%mod; _ln(a,d,n); for (int i=0;i<n;i++)d[i]=1ll*d[i]*k1%mod; _exp(d,b,n); } void _div(int *a,int *b,int *q,int *r,int n,int m){ static int c[N],d[N],e[N]; int len=n-m+1; for (int i=0;i<len;i++)c[i]=a[n-1-i]; for (int i=0;i<len;i++)d[i]=i<m?b[m-1-i]:0; _inv(d,e,len);mul(c,e,len,len),std::reverse(c,c+len); memcpy(q,c,4*len),mul(c,b,len,m); for (int i=0;i<m;i++)r[i]=dec(a[i],c[i]); } void cdq(int l,int r,int *f,int *g){ static int c[N]; if (l==r)return ; int mid=(l+r)>>1; cdq(l,mid,f,g);mul_2(f+l,g+1,c,mid-l+1,r-l); for (int i=mid+1;i<=r;i++)f[i]=add(f[i],c[i-l-1]); cdq(mid+1,r,f,g); }}using namespace Poly;int n,m;int a[N],b[N],Q[N],R[N];string k;void solve(){ scanf("%d",&n); for (int i=1;i<n;i++)scanf("%d",a+i);b[0]=1; cdq(0,n-1,b,a); print(b,n);}int main(){ int t=1; init_poly(); // scanf("%d",&t); while (t--){ solve(); } return 0;}变换
第一个定义式
变换的组合意义:无标号的个球,分成若干非空组,大小为的组内部具有中方案数,为最后的总方案数(如果两个组大小和内部方案相同,则他们不可区分)
注:在枚举有几个大小为的组,是大小为的内部的方案数
第二种定义式
分治
考虑分治区间
已经计算完
此时的值是已知的
又因为,在递归时,需保证的贡献已经计算
也就是说我们需要处理的对的的贡献
的下标是,由于要覆盖,所以的下标是
对于,我们保证转移的时候是正确求出的
所以在递归到时,我们在将乘上
这种相互递归的式子
我们仍然考虑分治区间
已经计算完的所有值,现在的问题是在上的值还没有计算完
条件很难满足
考虑我们能不能分别计算
现在应该是已知
我们若按照之前的算法计算
此时少了在上的贡献
我们考虑分治过程中的关系
只考虑分治到右边,左边同第一个
此时区间为,则在之后的任何区间内,都有
也就是
所以,只要,那么,
对时:
先计算
此时,只有是正确的,
继续递归到下个区间
现在,那么我们会有都是已知的
先计算完区间,
我们已经计算完
已知
所以我们需要计算
我们考虑为什么这是对的
的贡献来自
计算的贡献
计算与的交叉结果
由于所以,的内部交叉无贡献
发现我们每次这样计算的时候都是计算好了对后面区间的贡献
所以这样是正确的
即
时
时