Description
有一个集合U={1,2,…,n),要从中选择k个元素作为一个子集A。
若a∈A,则要有a*X不属于A,x是一个给定的数。
求可选方案对M取模后的值。
1< = N< = 10^18,2< = m< = 1000000,0< = K< = 1000,2< = x< = 10。
Input
第一行输入N,M,K,X
Output
如题
将不能共存的数连边,每个联通块都是一条链,计算出每个长度的链的条数,以及每个长度的链上取0~k个数的方案数,卷积可得答案。时间复杂度$O(klog(k)log(n)log_x(n))$
#include<cstdio> #include<cmath> #include<algorithm> typedef unsigned long long u64; typedef long double ld; const ld pi=std::acos(-1); struct cplx{ ld a,b; cplx(ld x=0,ld y=0):a(x),b(y){} cplx operator+(cplx x){return cplx(a+x.a,b+x.b);} cplx operator-(cplx x){return cplx(a-x.a,b-x.b);} cplx operator*(cplx x){return cplx(a*x.a-b*x.b,a*x.b+b*x.a);} cplx conj(){return cplx(a,-b);} }A[2111],B[2111],E[2][13][1111]; u64 n,pwx[77],ts[77]; int m,k,x,ppx=0,C[77][77],N,K; int ans[1111],tmp[1111],tmp2[1111],rev[2111]; void dft(cplx*a,int t){ for(int i=0;i<N;++i)if(i<rev[i])std::swap(a[i],a[rev[i]]); for(int i=1,z=0;i<N;i<<=1,++z){ cplx*e=E[t][z]; for(int j=0;j<N;j+=i<<1){ cplx*b=a+j,*c=b+i; for(int k=0;k<i;++k){ cplx x=b[k],y=c[k]*e[k]; b[k]=x+y; c[k]=x-y; } } } if(t)for(int i=0;i<N;++i)a[i].a/=N; } void mul(int*a,int*b){ for(int i=0;i<=k;++i)B[i]=cplx(a[i],b[i]); for(int i=k+1;i<N;++i)B[i]=0; dft(B,0); B[N]=B[0]; for(int i=0;i<N;++i){ cplx x=B[i],y=B[N-i].conj(); A[i]=cplx(0,0.25)*(y+x)*(y-x); } dft(A,1); for(int i=0;i<=k;++i)a[i]=((long long)(A[i].a+0.49))%m; } int main(){ scanf("%llu%d%d%d",&n,&m,&k,&x); C[0][0]=1; for(int i=0;i<70;++i){ for(int j=0;j<=i;++j){ (C[i+1][j]+=C[i][j])%=m; (C[i+1][j+1]+=C[i][j])%=m; } } for(pwx[ppx++]=1;(pwx[ppx]=pwx[ppx-1]*x)<=n;++ppx); for(int i=ppx-1;i>=0;--i){ ts[i]=n/pwx[i]; ts[i]-=ts[i]/x; } for(N=2,K=0;N<k*2+5;N<<=1,++K); for(int i=1;i<N;++i)rev[i]=rev[i>>1]>>1|(i&1)<<K; for(int i=1,z=0;i<N;i<<=1,++z){ for(int j=0;j<i;++j){ E[0][z][j]=cplx(cos(j*pi/i),sin(j*pi/i)); E[1][z][j]=E[0][z][j].conj(); } } ans[0]=1; for(int i=0;i<ppx;++i){ ts[i]-=ts[i+1]; for(int j=0;j<=k;++j)tmp[j]=(i+2-j>=0?C[i+2-j][j]:0),tmp2[j]=0; tmp2[0]=1; for(u64 t=ts[i];t;t>>=1,mul(tmp,tmp))if(t&1)mul(tmp2,tmp); mul(ans,tmp2); } printf("%d\n",ans[k]); return 0; }