BZOJ3992: [SDOI2015]序列统计
n<=1e9的序列,m<=8000是质数,给mod m下的s个不同数字,问:在序列里填集合中的数字,使最终序列里所有数的乘积mod m后为给定的x的序列有多少种。
喵喵题
首先可能可以往排列组合那边想,决定每个数选几个然后再全排列。但这个n有点大,行不通。
题目要求“选择若干项,求最终积为给定值的方案”,有一个方便解决的类似问题:“选择若干项,求最终和为给定值的方案”,这个是生成函数的经典应用。把值当下标,系数表示方案数,两个生成函数一成,选择的项数就相加。这样就可以多项式快速幂得到答案。
那就好了。
好了个头这里是乘法,mod意义下的乘法转加法--用指标!
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 //#include<math.h> 6 //#include<time.h> 7 //#include<complex> 8 #include<algorithm> 9 using namespace std; 10 11 int pp,m,n,wei,X,ls,mm,g; 12 #define maxn 20011 13 int c[maxn],a[maxn],ind[maxn]; 14 15 int powmod(int a,int b,int mod) 16 { 17 int ans=1; 18 while (b) 19 { 20 if (b&1) ans=1ll*ans*a%mod; 21 a=1ll*a*a%mod; b>>=1; 22 } 23 return ans; 24 } 25 26 int pr[maxn],lp; 27 int findroot(int x) 28 { 29 lp=0; 30 int tmp=x-1; 31 for (int i=2;1ll*i*i<=tmp;i++) if (tmp%i==0) 32 { 33 pr[++lp]=i; 34 while (tmp%i==0) tmp/=i; 35 } 36 if (tmp>1) pr[++lp]=tmp; 37 for (int i=2;i<=x-1;i++) 38 { 39 bool flag=1; 40 for (int j=1;j<=lp;j++) if (powmod(i,(x-1)/pr[j],x)==1) {flag=0; break;} 41 if (flag) return i; 42 } 43 } 44 45 const int mod=1004535809,G=findroot(mod); int rev[maxn]; 46 void dft(int *a,int n,int type) 47 { 48 for (int i=0;i<n;i++) if (i<rev[i]) {int t=a[i]; a[i]=a[rev[i]]; a[rev[i]]=t;} 49 for (int i=1;i<n;i<<=1) 50 { 51 int w=powmod(G,(mod-1)/(i<<1),mod); 52 if (type==-1) w=powmod(w,mod-2,mod); 53 for (int j=0,p=i<<1;j<n;j+=p) 54 { 55 int t=1; 56 for (int k=0;k<i;k++,t=1ll*t*w%mod) 57 { 58 int tmp=1ll*t*a[j+k+i]%mod; 59 a[j+k+i]=(a[j+k]-tmp+mod)%mod; 60 a[j+k]=(a[j+k]+tmp)%mod; 61 } 62 } 63 } 64 } 65 66 void ntt(int *a,int *b,int *c) 67 { 68 if (!rev[1]) for (int i=0;i<n;i++) 69 { 70 rev[i]=0; 71 for (int j=0;j<wei;j++) rev[i]|=((i>>j)&1)<<(wei-j-1); 72 } 73 dft(a,n,1); dft(b,n,1); 74 for (int i=0;i<n;i++) c[i]=1ll*a[i]*b[i]%mod; 75 dft(c,n,-1); int inv=powmod(n,mod-2,mod); 76 for (int i=0;i<n;i++) c[i]=1ll*c[i]*inv%mod; 77 for (int i=0;i<=mm-2;i++) c[i]=(c[i]+c[i+mm-1])%mod,c[i+mm-1]=0; 78 } 79 80 int hh[maxn],hhh[maxn]; 81 void powmod2(int *a,int b,int *ans) 82 { 83 bool flag=1; 84 while (b) 85 { 86 if (b&1) 87 { 88 if (flag) memcpy(ans,a,sizeof(hh)),flag=0; 89 else 90 { 91 memcpy(hh,ans,sizeof(hh)); 92 memcpy(hhh,a,sizeof(hhh)); 93 ntt(hh,hhh,ans); 94 } 95 } 96 b>>=1; 97 memcpy(hh,a,sizeof(hh)); 98 memcpy(hhh,a,sizeof(hhh)); 99 ntt(hh,hhh,a); 100 } 101 } 102 103 int ans[maxn]; 104 int main() 105 { 106 scanf("%d%d%d%d",&pp,&mm,&X,&ls); 107 for (int i=1,x;i<=ls;i++) scanf("%d",&x),c[x]=1; 108 g=findroot(mm); ind[1]=0; 109 for (int i=g,cnt=1;i!=1;i=i*1ll*g%mm,cnt++) ind[i]=cnt; 110 for (int i=1;i<=mm-1;i++) a[ind[i]]=c[i]; 111 m=mm-2+mm-2; for (n=1,wei=0;n<=m;n<<=1,wei++); 112 powmod2(a,pp,ans); 113 printf("%d\n",ans[ind[X]]); 114 return 0; 115 }