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;
    }
    
  • 相关阅读:
    多年收集的一些稀有软件1
    Object-C中使用NSKeyedArchiver归档(将各种类型的对象存储到文件中)
    转-- iOS 30多个iOS常用动画,带详细注释
    转-ios设备唯一标识获取策略
    微信授权
    Windows服务Demo
    查询某个时间段在另一个时间段里面的时间
    微服务官方文档链接
    c# html 转word
    Unreal4 入门(配置)
  • 原文地址:https://www.cnblogs.com/wxjor/p/9570810.html
Copyright © 2011-2022 走看看