orz zrf wjh
时间限制 5S
空间限制 512MB
解法
笔者本来想推出dp式子,但是一直解决不了去重的问题,请教dalao后知道了直接用生成函数的做法:
首先设环的生成函数为
F
(
x
)
=
∑
i
∈
a
x
i
F(x)=\sum_{i\in a} x^i
F(x)=∑i∈axi
然后直接求F(x)的exp,第1到n项的系数就是答案了。这个时候是无标号的方案数。
这个是因为F(x)相当于求只有一个环时的合法解,exp以后就是任意多个环组合在一起的合法解。
然后考虑怎么把答案转化成有标号的:最终的答案每一项都乘上一个
i
!
i!
i!,但是这个时候一个长度为i的环的方案被多算了i次。所以需要在一开始的生成函数中每一项乘
1
i
\frac{1}{i}
i1
#include<bits/stdc++.h>
using namespace std;
const int maxn=4e5+5;
const int mod=950009857;
inline int read(){
char c=getchar();int t=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n;
int f[maxn],g[maxn],inv[maxn];
inline int ksm(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;b>>=1;
}
return ans;
}
inline int am(int x){
return x>=mod?x-mod:x;
}
int r[maxn];
inline void ntt(int a[],int lim,int f){
for(int i=1;i<lim;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wg=ksm(7,(mod-1)/(i<<1));
if(f==-1)wg=ksm(wg,mod-2);
for(int j=0;j<lim;j+=(i<<1)){
int wn=1;
for(int k=0;k<i;k++,wn=1ll*wn*wg%mod){
int x=a[j+k],y=1ll*a[j+k+i]*wn%mod;
a[j+k]=am(x+y),a[j+k+i]=am(x-y+mod);
}
}
}
if(f==1)return ;
int inv2=ksm(lim,mod-2);
for(int i=0;i<lim;i++)a[i]=1ll*a[i]*inv2%mod;
}
int A[maxn],lim,l;
void getinv(int a[],int b[],int n){
if(n==1){b[0]=ksm(a[0],mod-2);return ;}
getinv(a,b,(n+1)>>1);
lim=1,l=0;
while(lim<(n<<1))lim<<=1,l++;
for(int i=1;i<lim;i++)r[i]=r[i>>1]>>1|(i&1)<<(l-1);
for(int i=0;i<n;i++)A[i]=a[i];
for(int i=n;i<lim;i++)A[i]=0;
ntt(A,lim,1);ntt(b,lim,1);
for(int i=0;i<lim;i++)b[i]=1ll*b[i]*am(2ll+mod-1ll*A[i]*b[i]%mod)%mod;
ntt(b,lim,-1);
for(int i=n;i<lim;i++)b[i]=0;
}
int a2[maxn],b2[maxn];
void dao(int a[],int b[],int n){
for(int i=0;i<n-1;i++)b[i]=1ll*(i+1)*a[i+1]%mod;
}
void jifen(int a[],int b[],int n){
for(int i=n-1;i>0;i--)b[i]=1ll*inv[i]*a[i-1]%mod;
}
void ln(int a[],int b[],int n){
for(int i=0;i<(n<<2);i++)b[i]=0;
getinv(a,b,n);
lim=1,l=0;
while(lim<(n<<1))lim<<=1,l++;
for(int i=1;i<lim;i++)r[i]=r[i>>1]>>1|(i&1)<<(l-1);
dao(a,a2,n);
for(int i=n-1;i<lim;i++)a2[i]=0;
ntt(a2,lim,1);ntt(b,lim,1);
for(int i=0;i<lim;i++)b[i]=1ll*b[i]*a2[i]%mod;
ntt(b,lim,-1);
jifen(b,b,n);
for(int i=n;i<lim;i++)b[i]=0;
b[0]=0;
}
int lnb[maxn];
void exp(int a[],int b[],int n){
if(n==1){
b[0]=1;return ;
}
exp(a,b,(n+1)>>1);
ln(b,lnb,n);
lim=1,l=0;
while(lim<(n<<1))lim<<=1,l++;
for(int i=1;i<lim;i++)r[i]=r[i>>1]>>1|(i&1)<<(l-1);
for(int i=0;i<n;i++)lnb[i]=am(a[i]-lnb[i]+mod);
for(int i=n;i<lim;i++)lnb[i]=b[i]=0;
lnb[0]++;
ntt(lnb,lim,1);ntt(b,lim,1);
for(int i=0;i<lim;i++)b[i]=1ll*b[i]*lnb[i]%mod;
ntt(b,lim,-1);
for(int i=n;i<lim;i++)b[i]=0;
}
int rec[maxn];
int main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
n=read();int k=read();
inv[1]=1;rec[1]=1;
for(int i=2;i<=n;i++){inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;rec[i]=1ll*rec[i-1]*i%mod;}
for(int i=1;i<=k;i++){
int x=read();
f[x]=inv[x];
}
exp(f,g,n+1);
for(int i=1;i<=n;i++)printf("%d\n",1ll*g[i]*rec[i]%mod);
return 0;
}