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

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 
#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*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;mm<<=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;mm<<=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;W00<<=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;
}

你可能感兴趣的:(FFT-NNT)