首页 > 代码库 > bzoj3992 [SDOI2015]序列统计

bzoj3992 [SDOI2015]序列统计

Description

小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S。
小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题 的答案可能很大,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。

Input

一行,四个整数,N、M、x、|S|,其中|S|为集合S中元素个数。第二行,|S|个整数,表示集合S中的所有元素。

Output

一行,一个整数,表示你求出的种类数mod 1004535809的值。

Sample Input

4 3 1 2
1 2

Sample Output

8

HINT

【样例说明】
可以生成的满足要求的不同的数列有(1,1,1,1)、(1,1,2,2)、(1,2,1,2)、(1,2,2,1)、(2,1,1,2)、(2,1,2,1)、(2,2,1,1)、(2,2,2,2)。
【数据规模和约定】
对于10%的数据,1<=N<=1000;
对于30%的数据,3<=M<=100;
对于60%的数据,3<=M<=800;
对于全部的数据,1<=N<=109,3<=M<=8000,M为质数,1<=x<=M-1,输入数据保证集合S中元素不重复

 

正解:$DP$+$NTT$。

首先考虑暴力$DP$,$f[i][j]$表示统计到第$i$位,乘积为$j$的方案数,然后很显然,$f[i][(k*p)\mod m]=f[i-1][k]*sum[p]$,其中$sum[p]$为p这个数出现的次数。

但是这样是肯定会$T$飞的,所以我们考虑优化。话说这个优化还是蛮玄学的。。

我们可以把乘法变成加法,然后两个数相乘就是它们的对数相加,当然底数要相同,并且对数肯定要是整数。

因为$m$是质数,所以$m$必定有原根。我们又知道,原根的$[1,m-1]$次方对应了$[1,m-1]$这些数,所以我们可以求出$[1,m-1]$的离散对数,也就是使得原根$g^{x}=i$的$x$(然而我没学过所以不会。。)

设$ind[i]$为$i$在模$m$意义下的离散对数,于是$f[i][(ind[k]+ind[p])\mod (m-1)]=f[i-1][ind[k]]*sum[ind[p]]$(注意这里第二维的取值范围是$m-1$,所以还要加一个特判)

因为答案对$1004535809$取模,所以显然这个方程可以用$NTT$优化,但是$n$的范围很大,有$10^{9}$级别,不过我们在卷积外面套一个快速幂就行了。

我们先用快速幂算出$sum$的$n$次方,然后再用$f[0]*sum$,最后输出$f[n][ind[x]]$,就是我们所要的答案。

 

  1 //It is made by wfj_2048~  2 #include <algorithm>  3 #include <iostream>  4 #include <complex>  5 #include <cstring>  6 #include <cstdlib>  7 #include <cstdio>  8 #include <vector>  9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define rhl (1004535809) 15 #define inf (1<<30) 16 #define NN (100010) 17 #define G (3) 18 #define il inline 19 #define RG register 20 #define ll long long 21 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 22  23 using namespace std; 24  25 int rev[NN],ind[NN],N,n,m,x,s,lg,gg; 26 ll ans[NN],a[NN],b[NN],sum[NN]; 27  28 il int gi(){ 29     RG int x=0,q=1; RG char ch=getchar(); 30     while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 31     if (ch==-) q=-1,ch=getchar(); 32     while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 33     return q*x; 34 } 35  36 il ll qpow(RG ll a,RG ll b){ 37     RG ll ans=1; 38     while (b){ 39     if (b&1) (ans*=a)%=rhl; 40     (a*=a)%=rhl,b>>=1; 41     } 42     return ans; 43 } 44  45 il void NTT(ll *a,RG int n,RG int f){ 46     for (RG int i=0;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]); 47     for (RG int i=1;i<n;i<<=1){ 48     RG ll gn=qpow(G,(rhl-1)/(i<<1)),x,y; 49     for (RG int j=0;j<n;j+=(i<<1)){ 50         RG ll g=1; 51         for (RG int k=0;k<i;++k,(g*=gn)%=rhl){ 52         x=a[j+k],y=g*a[j+k+i]%rhl; 53         a[j+k]=(x+y)%rhl,a[j+k+i]=(x-y+rhl)%rhl; 54         } 55     } 56     } 57     if (f==1) return; reverse(a+1,a+n); RG ll inv=qpow(n,rhl-2); 58     for (RG int i=0;i<n;++i) (a[i]*=inv)%=rhl; 59     for (RG int i=m;i<n;++i) (a[i%(m-1) ? i%(m-1) : m-1]+=a[i])%=rhl,a[i]=0; return; 60 } 61  62 il void NTTpow(ll *a,RG int b){ 63     for (RG int i=0;i<N;++i) ans[i]=a[i]; b--; 64     while (b){ 65     NTT(a,N,1); 66     if (b&1){ 67         NTT(ans,N,1); 68         for (RG int i=0;i<N;++i) (ans[i]*=a[i])%=rhl; 69         NTT(ans,N,-1); 70     } 71     for (RG int i=0;i<N;++i) (a[i]*=a[i])%=rhl; 72     NTT(a,N,-1); b>>=1; 73     } 74     for (RG int i=0;i<N;++i) a[i]=ans[i]; return; 75 } 76  77 il int isroot(RG int x){ 78     RG int l=1; 79     for (RG int i=1;i<m-1;++i){ 80     (l*=x)%=m; 81     if (l==1) return 0; 82     } 83     return 1; 84 } 85  86 il void pre(){ 87     for (RG int i=2;i<m;++i) if (isroot(i)){ gg=i; break; } 88     RG int l=1; for (RG int i=1;i<m;++i) (l*=gg)%=m,ind[l]=i; return; 89 } 90  91 il void work(){ 92     n=gi(),m=gi(),x=gi(),s=gi(); pre(); 93     for (RG int i=1,v;i<=s;++i) sum[ind[v=gi()]]++; 94     for (N=1;N<=(m<<1);N<<=1) lg++; a[ind[1]]=1,sum[0]=0; 95     for (RG int i=0;i<N;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)); 96     NTTpow(sum,n); NTT(a,N,1),NTT(sum,N,1); 97     for (RG int i=0;i<N;++i) (a[i]*=sum[i])%=rhl; 98     NTT(a,N,-1); printf("%lld",a[ind[x]]); return; 99 }100 101 int main(){102     File("sequence");103     work();104     return 0;105 }

 

bzoj3992 [SDOI2015]序列统计