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 }
View Code

 

posted @ 2018-02-26 09:54  Blue233333  阅读(193)  评论(0编辑  收藏  举报