zoukankan      html  css  js  c++  java
  • [SDOI2015]序列统计

    FFT优化背包

    可以推出dp式子

    乘法不可做。M是质数,变成原根

    dp式子现在是加法

    其实每次是原来的f数组,对可以转移的s集合进行卷积(即FFT优化背包)

    直接快速幂搞定

    详细一些:

    循环卷积无非就是多了一个取值的位置,每次FFT之后,一个位置再变成两个位置的和,剩下>=m的位置再变成0

    也有结合律

    注意,S中有0,而0没有原根,并且x>=1所以选择0一定不是答案。直接pass掉

    代码:

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    #define int long long
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=8005*8;
    const int mod=1004535809;
    int n,m,o;
    int len;
    int G;
    int s[N],sz;
    ll ret[N];
    ll qm(ll x,ll y,int mo){
        ll ret=1;
        while(y){
            if(y&1) ret=ret*x%mo;
            x=x*x%mo;
            y>>=1;
        }
        return ret;
    }
    ll f[N],h[N];
    int id[N];
    int rev[N];
    void fft(ll *f,int n,int c){
        for(reg i=0;i<n;++i){
            if(i<rev[i]) swap(f[i],f[rev[i]]);
        }
        for(reg p=2;p<=n;p<<=1){
            int gen;
            if(c==1) gen=qm(3,(mod-1)/p,mod);
            else gen=qm(qm(3,mod-2,mod),(mod-1)/p,mod);
            int len=p/2;
            for(reg l=0;l<n;l+=p){
                ll buf=1;
                for(reg k=l;k<l+len;++k){
                    ll tmp=buf*f[k+len]%mod;
                    f[k+len]=(f[k]-tmp+mod)%mod;
                    f[k]=(f[k]+tmp)%mod;
                    buf=buf*gen%mod;
                }
            }
        }
    }
    void calc(ll *f,ll *g,int n){
    //    cout<<"clac nn "<<n<<endl;
    //    cout<<" fff "<<endl;
    //    for(reg i=0;i<n;++i){
    //        cout<<f[i]<<" ";
    //    }cout<<endl;
    //    cout<<" ggg "<<endl;
    //    for(reg i=0;i<n;++i){
    //        cout<<g[i]<<" ";
    //    }cout<<endl;
        
        for(reg i=0;i<n;++i) h[i]=g[i];
        fft(f,n,1);fft(h,n,1);
        for(reg i=0;i<n;++i) f[i]=f[i]*h[i]%mod;
        fft(f,n,-1);
        ll inv=qm(n,mod-2,mod);
        for(reg i=0;i<n;++i) f[i]=f[i]*inv%mod,h[i]=f[i];
        for(reg i=1;i<m;++i) {
        //    cout<<f[i]<<" ";
            f[i]=(f[i]+h[i+m-1])%mod;
        }
    //    cout<<endl;
        for(reg i=m;i<n;++i) f[i]=0;
    }
    void findG(){
        for(G=2;;++G){
            bool fl=true;
            for(reg i=1;i<=m-2;++i){
                if(qm(G,i,m)==1) {
                    fl=false;break;
                }
            }
            if(fl) break;
        }    
    }
    void qsm(int y){
        memset(ret,0,sizeof ret);
        ret[0]=1;
        while(y){
            if(y&1) {
                if(ret[0]==1) memcpy(ret,f,sizeof f);
                else calc(ret,f,len);
            }
            calc(f,f,len);
    //        /cout<<" ff "<<y<<endl;
    //        for(reg i=0;i<n;++i){
    //            cout<<f[i]<<" ";
    //        }cout<<endl;
            y>>=1;
        }
    }
    int main(){
        rd(n);rd(m);rd(o);rd(sz);
        int cnt=0;
        int lp;
        for(reg i=1;i<=sz;++i){
            rd(lp);if(lp) s[++cnt]=lp;
        }
        findG();
    //    cout<<" GG "<<G<<endl;
        for(reg i=1;i<=m-1;++i){
            id[qm(G,i,m)]=i;
        }
        for(reg i=1;i<=cnt;++i) {
            s[i]=id[s[i]];
            f[s[i]]=1;
        }
        for(lp=m+m,len=1;len<lp;len<<=1);
        for(reg i=0;i<len;++i){
            rev[i]=rev[i>>1]>>1|((i&1)?len>>1:0);
        }
    //    cout<<" len "<<len<<endl;
        qsm(n);
        o=id[o];
    //    cout<<" o "<<o<<endl;
        printf("%lld",ret[o]);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/1/16 21:29:34
    */
  • 相关阅读:
    实例属性 类属性 实例域 类域
    研究数据集
    static 静态域 类域 静态方法 工厂方法 he use of the static keyword to create fields and methods that belong to the class, rather than to an instance of the class 非访问修饰符
    accessor mothod mutator mothod 更改器方法 访问器方法 类的方法可以访问类的任何一个对象的私有域!
    上钻 下钻 切片 转轴 降采样
    识别会话
    Performance Tuning Using Linux Process Management Commands
    Secure Hash Algorithm 3
    grouped differently across partitions
    spark 划分stage Wide vs Narrow Dependencies 窄依赖 宽依赖 解析 作业 job stage 阶段 RDD有向无环图拆分 任务 Task 网络传输和计算开销 任务集 taskset
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10283605.html
Copyright © 2011-2022 走看看