zoukankan      html  css  js  c++  java
  • [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中的所有元素。1<=N<=10^9,3<=M<=8000,M为质数0<=x<=M-1,输入数据保证集合S中元素不重复x∈[1,m-1]
    集合中的数∈[0,m-1]

    Output

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

    Sample Input

    4 3 1 2
    1 2

    Sample Output

    8
    【样例说明】可以生成的满足要求的不同的数列有(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)

    试题分析

    原根的一类性质:设(p)(mod)的原根,那么(p^0 o p^{mod-2} pmod{mod})可以表示出1~mod-1的所有数。
    这样我们就可以对于每个数求指标((p^x=y),其中(x)(y)的指标),然后我们就可以把乘法变成指数上的加法,NTT多项式快速幂即可。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
     
    using namespace std;
    #define LL long long
    #define G 3
    #define Mod 1004535809LL
     
    inline LL read(){
        LL x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const LL MAXN = 100010;
    const LL INF = 2147473600;
     
    LL N,M,X,S; LL top,rev[MAXN+1];
    LL s[MAXN+1],sta[MAXN+1];
    LL a[MAXN+1];
     
    inline LL Pow(LL A,LL B,LL P){
        LL res=1;
        while(B){
            if(B&1) res=res*A%P;
            A=A*A%P; B>>=1;
        } return res;
    } 
    inline LL GetN(LL x){
        LL y=x-1;
        for(LL i=2;y!=1;i++) {
            if(y%i==0) sta[++top]=i;
            while(y%i==0) y/=i;
        }
        for(LL i=2;;i++){
            bool flag=1;
            for(LL j=1;j<=top;j++)
                if(Pow(i,(x-1)/sta[j],x)==1) {flag=false; break;}
            if(flag) return i;
        }
    }
    LL a1[MAXN+1],b1[MAXN+1],c1[MAXN+1],b[MAXN+1],t[MAXN+1];
    inline void NTT(LL *A,LL lim,LL type){
        for(LL i=0;i<lim;i++) if(rev[i]>i) swap(A[rev[i]],A[i]);
        for(LL mid=1;mid<lim;mid<<=1){
            LL Wn = Pow(G , type==1?(Mod-1)/(mid<<1):(Mod-1-(Mod-1)/(mid<<1)) , Mod)%Mod;//-
            for(LL R=mid<<1,j=0;j<lim;j+=R){
                LL w = 1;
                for(LL k=0;k<mid;k++){
                    LL x=A[j+k] , y=w*A[j+k+mid]%Mod; //-
                    A[j+k]=(x+y)%Mod; A[j+k+mid]=(x-y%Mod+Mod)%Mod;
                    w=w*Wn%Mod;
                }
            }
        } if(type==1) return ; //reverse(A+1,A+lim); 
        LL INV=Pow(lim,Mod-2,Mod)%Mod;
        for(LL i=0;i<lim;i++) A[i]=A[i]*INV%Mod; return ;
    }
    LL lim=1;
    inline void Mul(LL *A,LL *B,LL *C){
        for(LL i=0;i<M;i++) a1[i]=B[i],b1[i]=C[i];
        for(LL i=M;i<lim;i++) a1[i]=b1[i]=0;
        NTT(a1,lim,1); NTT(b1,lim,1);
        for(LL i=0;i<lim;i++) A[i]=a1[i]*b1[i]%Mod;
        NTT(A,lim,-1);
        for(LL i=lim-1;i>=M-1;i--){
            A[i%(M-1)]=(A[i%(M-1)]+A[i])%Mod; A[i]=0;
        } return ;
    }
     
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        N=read(),M=read(),X=read(),S=read(); LL Now=1LL,T=GetN(M);
        for(LL i=0;i<M-1;i++) t[Now]=i,Now=Now*T%M;//cout<<Now<<" "<<T<<endl;
        for(LL i=1;i<=S;i++) {LL x=read()%Mod; if(x) a[t[x]]++; } lim=1; int l=0;
        while(lim<=2*(M-1)) lim<<=1,++l;
        for(LL i=0;i<lim;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
        memset(b,0,sizeof(b)); b[0]=1;
        while(N){
            if(N&1) Mul(b,a,b);
            Mul(a,a,a); N>>=1;
        } printf("%lld
    ",b[t[X]]%Mod);
        return 0;
    }
    
  • 相关阅读:
    HDU 4472 Count DP题
    HDU 1878 欧拉回路 图论
    CSUST 1503 ZZ买衣服
    HDU 2085 核反应堆
    HDU 1029 Ignatius and the Princess IV
    UVa 11462 Age Sort
    UVa 11384
    UVa 11210
    LA 3401
    解决学一会儿累了的问题
  • 原文地址:https://www.cnblogs.com/wxjor/p/9570810.html
Copyright © 2011-2022 走看看