• 「SDOI2015」序列统计


    题目链接:Click here

    Solution:

    容易得到这样一个(dp),设(f[i][j])表示已经选了(i)个数,乘积(mod \,\,m)后为(j)的方案

    [f[2 imes i][j]=sum_{a imes bequiv j\,\,(mod\,\, m)} f[i][a] imes f[i][b] ]

    考虑如何优化这个转移方程,注意到这道题的模数为(1004535809),这是一个很大的提示,考虑(NTT)

    但是我们知道(NTT)处理的是卷积,而这里是指数相乘,该怎么转化呢?

    乘法变加法,不由得让我们想到对数,模意义下的对数,又不由得让我们想到原根

    考虑原根的定义,(g)(p)的原根,则(g^0 ,g^1dots g^{p-2})(mod \,\,p)下恰好取到([1,p-1])的所有整数

    原根也很好求,把(varphi(p)=prod pr_i^{a_i}),然后对于所有的(pr_i)都有(g^{varphi(p) over pr_i} ot equiv 1 \,\, ( mod \,\, p))

    那么我们令(j=log_g j,a=log_g a,b=log_g b),同时根据扩展欧拉定理,转移方程就变成了

    [f[2 imes i][j]=sum_{a+b equiv j \,\, (mod \,\, varphi(m))}f[i][a] imes f[i][b] ]

    注意每次转移后(f[i][j]+=f[i][j+varphi(m)]),我们就可以愉快的(NTT)啦!

    等等,好像还不行,(n=1e9),仔细观察这个转移,发现可以直接多项式快速幂,那么再快速幂即可,时间复杂度(O(mlog m log n))

    Code:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=3e4+11;
    const int mod=1004535809;
    int n,m,S,X,len=1,tim;
    int f[N],v[N],p[N],pr[N],lg[N];
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    int qpow(int x,int y,int p){
        int re=1;
        while(y>0){
            if(y&1) re=re*x%p;
            y>>=1;x=x*x%p;
        }return re;
    }
    int GetRt(int x){
        int tot=0,phi=x-1;
        for(int i=2;i*i<=phi;i++)
            if(phi%i==0){
                pr[++tot]=i;
                while(phi%i==0) phi/=i;
            }
        if(phi>1) pr[++tot]=phi;
        phi=x-1;
        for(int i=2;i<=phi;i++){
            int flag=1;
            for(int j=1;j<=tot&&flag;j++)
                if(qpow(i,phi/pr[j],x)==1) flag=0;
            if(flag) return i;
        }
        return -1;
    }
    void NTT(int *a,int flag){
        for(int i=0;i<len;i++)
            if(i<p[i]) swap(a[i],a[p[i]]);
        for(int l=2;l<=len;l<<=1){
            int wn=qpow(3,(mod-1)/l,mod);
            if(flag==-1) wn=qpow(wn,mod-2,mod);
            for(int st=0;st<len;st+=l){
                int w=1;
                for(int u=st;u<st+(l>>1);u++,w=w*wn%mod){
                    int x=a[u],y=w*a[u+(l>>1)]%mod;
                    a[u]=(x+y)%mod;a[u+(l>>1)]=(x+mod-y)%mod;
                }
            }
        }
    }
    void Mul(int *A,int *B,int *C){
        static int a[N],b[N];
        for(int i=0;i<len;i++) a[i]=A[i];
        for(int i=0;i<len;i++) b[i]=B[i];
        NTT(a,1);NTT(b,1);
        for(int i=0;i<len;i++) a[i]=a[i]*b[i]%mod;
        NTT(a,-1);int inv=qpow(len,mod-2,mod);
        for(int i=0;i<len;i++) a[i]=a[i]*inv%mod;
        for(int i=0;i<m-1;i++) C[i]=(a[i]+a[i+m-1])%mod;
    }
    signed main(){
        n=read(),m=read(),X=read(),S=read();
        while(len<(m<<1)) len<<=1,++tim;
        for(int i=0;i<len;i++)
            p[i]=(p[i>>1]>>1)|((i&1)<<(tim-1));
        int g=GetRt(m);
        for(int i=0;i<m-1;i++) lg[qpow(g,i,m)]=i;
        for(int i=1;i<=S;i++){
            int x=read()%m;
            if(x) ++v[lg[x]];
        }
        f[lg[1]]=1; 
        while(n){
            if(n&1) Mul(f,v,f);
            n>>=1;Mul(v,v,v);
        }
        printf("%lld
    ",f[lg[X]]);
        return 0;
    }
    
    
  • 相关阅读:
    OpenSSL生成证书、密钥
    js中对String去空格
    正则表达式
    webapi调用
    记一次完整的CI持续集成配置过程(.net core+Jenkins+Gitea)
    处理asp.net core连接mysql的一个异常Sequence contains more than one matching element
    asp.net core 3.1+mysql8.0+Hangfire遇到的异常解决记
    升级到asp.net core 3.1遇到的json异常
    了解ASP.NET Core端点路由
    asp.net core 2.2升到3.1遇到的问题小记
  • 原文地址:https://www.cnblogs.com/NLDQY/p/12242664.html
Copyright © 2020-2023  润新知