【JZOJ 4051】【SDOI2015第1轮第1试】序列统计

来源:互联网 发布:网络宣传有什么好处 编辑:程序博客网 时间:2024/06/10 23:05

Description

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

Solution

FFT/NNT练习题目
解法是先把暴力Dp式子写出来,因为里面有乘法,把乘法转成幂次的加,这样就变成了多项式乘法了,
当然要求原根

复杂度:O(log(N)Mlog(M))

Code

#include <cstdio>#define fo(i,a,b) for(int i=a;i<=b;++i)using namespace std;typedef long long LL;const int N=8500,mo=1004535809;int read(int &n){    char ch=' ';int q=0,w=1;    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());    if(ch=='-')w=-1,ch=getchar();    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;}int m,n,n1,m1,R;int a[N];LL ans;LL f[N*4],Ans[N*4],c[N*4];LL W[N*4],W0,niy;LL ksm(LL q,int w,int MO=mo){    LL ans=1;q%=MO;    for(;w;w>>=1,q=q*q%MO)if(w&1)ans=ans*q%MO;    return ans;}LL ROK(int q,int n){    int w=n-1;    for(int i=2;i*i<=w;++i)if(w%i==0)    {        for(;w%i==0;w=w/i);        if(1==ksm(q,(n-1)/i,n))return 0;    }    if(w-1)return 1!=ksm(q,(n-1)/w,n);    return 1;}void DFT(LL *a,int n,int ws,int K){    fo(i,0,n-1)    {        int q=0;        for(int j=i,w=ws;w;w--,j>>=1)q=(q<<1)+(j&1);        c[q]=a[i];    }    for(int I=2;I<=n;I<<=1)    {        int mid=I>>1;        fo(i,0,mid-1)        {            LL w=(K>0)?(W[W0/I*i]):(W[W0-W0/I*i]);            for(int j=i;j<n;j+=I)            {                LL t=w*c[j+mid]%mo;                c[j+mid]=(c[j]-t)%mo;                c[j]=(c[j]+t)%mo;            }        }    }    if(K<0)fo(i,0,n-1)c[i]=c[i]*niy%mo;}void FFTpre(){    int m,ws;    for(m=1,ws=1;m<n;m<<=1,ws++);    m<<=1;    DFT(f,m,ws,1);    fo(i,0,m)f[i]=c[i]*c[i]%mo;    DFT(f,m,ws,-1);    fo(i,0,n-1)f[i]=c[i];    fo(i,n,m)f[i%n]=(f[i%n]+c[i])%mo,f[i]=0;}void FFT(){    int m,ws;    for(m=1,ws=1;m<n;m<<=1,ws++);    m<<=1;    DFT(Ans,m,ws,1);    fo(i,0,m)Ans[i]=c[i];    DFT(f,m,ws,1);    fo(i,0,m)Ans[i]=Ans[i]*c[i]%mo;    DFT(Ans,m,ws,-1);    fo(i,0,n-1)Ans[i]=c[i];    fo(i,n,m)Ans[i%n]=(Ans[i%n]+c[i])%mo,Ans[i]=0;}void ksm(int w){    Ans[0]=1;    for(;w;w>>=1,FFTpre())if(w&1)FFT();}int main(){    freopen("!.in","r",stdin);//  freopen(".out","w",stdout);    int q;    read(n1),read(n),read(m),read(m1);    fo(i,1,m1)a[read(q)%n]++;    fo(i,2,n-1)if(ROK(i,n)){R=i;break;}    --n;q=1;    fo(i,0,n-1)f[i]=a[q],q=q*R%(n+1);    for(W0=1;W0<n;W0<<=1);W0<<=1;    W[0]=1;W[1]=ksm(3,(mo-1)/W0);niy=ksm(W0,mo-2);    fo(i,2,W0)W[i]=W[i-1]*W[1]%mo;    ksm(n1);    ans=0;    q=1;    fo(i,0,n-1)    {        if(q==m)ans+=Ans[i];        q=q*R%(n+1);    }    printf("%lld\n",(ans+mo)%mo);    return 0;}