zoukankan      html  css  js  c++  java
  • [bzoj4197] [NOI2015]寿司晚宴

    题目链接

    状压(dp).

    对于(30\%)的数据,(nleq 30),质因数的种类最多只有10个,所以可以压缩状态,设状态(sta)为第(i)位为集合中是否有第(i)个质因数。

    (f[i][s1][s2])表示当前考虑到第(i)个数,第一个集合状态为(s1),第二个集合状态为(s2)的方案数。

    设当前枚举到的数状态为(k),显然有转移:(f[i][s1|k][s2]+=f[i-1][s1][s2])(f[i][s1][s2|k]+=f[i-1][s1][s2]).

    这种刷表转移,根据套路,可以逆循环省掉第一维,时间复杂度(O(n*2^{20})).

    然后对于所有数据,上面的算法就不行了。但是看一眼数据范围:(nleq 500),还是很小。

    可以发现500的范围最多只能有一个大于22的质数,而小于22的质数只有8个。于是先按这个大一点的质数排序,然后一个一个质数的处理。

    (f[i][s1][s2])表示当前做到第(i)个质数了,前8个质数的状态为(s1,s2)的方案数。注意没有比22大的质数的数算一类。

    对于当前枚举到的质数(p),设(g[0/1][s1][s2])表示状态为(s1,s2),当前质数p给第一个/第二个人,且算上质数p及以前的质数的方案数,然后(g)的初值可以设为上一个质数的(f).这表示不含当前质数的方案数。然后(g)的转移可以按照30分的方法转移。

    当枚举到含有质数p的最后一个数时,转移完(g)时可以利用(g)来更新(f)

    [f[i][s1][s2]=g[0][s1][s2]+g[1][s1][s2]-f[i-1][s1][s2] ]

    因为(g[0])(g[1])都含有不选质数p的情况,所以要减去一个。

    然后发现(f)的第一维还是可以省掉,时间复杂度(O(n*2^{16}))

    #pragma GCC optimize("Ofast")
    #include<bits/stdc++.h>
    using namespace std;
    #define int long long 
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);x*=f;
    }
    void print(int x) {
        if(x<0) x=-x,print(x/10);
        if(!x) return ;print(x/10);putchar((x%10)^48);
    }void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    int n,f[300][300],g[300][300][2];
    int pri[]={0,2,3,5,7,11,13,17,19};
    struct node {
        int p,s;
        void init(int x) {
            int num=x;
            for(int i=1;i<=8;i++)
                if(!(num%pri[i])) {
                    s|=1<<(i-1);
                    while(!(num%pri[i])) num/=pri[i];
                }p=num;
        }
        bool operator < (const node x) const {return p<x.p;}
    }a[1000];int mod;
    void out(int x) {
        char s[10];
        //itoa(x,s,2);
        printf("%s
    ",s);
    }
    int add(int x,int y) {x+=y;if(x>mod) x-=mod;if(x<0) x+=mod;return x;}
    signed main() {
        read(n),read(mod);for(int i=2;i<=n;i++) a[i].init(i);
        //for(int i=2;i<=n;i++) out(a[i].s);
        sort(a+2,a+n+1);f[0][0]=1;
        for(int i=2;i<=n;i++) {
            if(a[i].p!=a[i-1].p||a[i].p==1||i==2)
                for(int s1=0;s1<=255;s1++)
                    for(int s2=0;s2<=255;s2++)
                        g[s1][s2][0]=g[s1][s2][1]=f[s1][s2]%mod;
            for(int s1=255;~s1;s1--)    
                for(int s2=255;~s2;s2--) {
                    if(!(a[i].s&s1)) g[s1][s2|a[i].s][1]=(g[s1][s2|a[i].s][1]+g[s1][s2][1])%mod;
                    if(!(a[i].s&s2)) g[s1|a[i].s][s2][0]=(g[s1|a[i].s][s2][0]+g[s1][s2][0])%mod;
                }
            if(a[i].p!=a[i+1].p||a[i].p==1||i==n) 
                for(int s1=0;s1<=255;s1++)
                    for(int s2=0;s2<=255;s2++)
                        f[s1][s2]=((g[s1][s2][0]+g[s1][s2][1]-f[s1][s2])%mod+mod)%mod;
        }
        int ans=0;
        for(int s1=0;s1<=255;s1++)
            for(int s2=0;s2<=255;s2++)
                if(!(s1&s2)) ans=(ans+f[s1][s2])%mod;
        write(ans);
        return 0;
    }
    
    
  • 相关阅读:
    获取aspx页面执行时间完全解决方案
    WebForm中DataGrid的20篇经典文章
    不走寻常路 设计ASP.NET应用程序的七大绝招
    动态绑定dropdownlist 开始拣.NET
    Notes中几个处理多值域的通用函数
    Lotus开发之Lotus Notes中域的验证
    Undokumentierte @Formeln/LotusScript im Lotus Notes Client/Server
    domino server端的Notes.ini详解
    Lotus开发基本性能优化
    以Ajax方式显示Lotus Notes视图的javasript类库NotesView2
  • 原文地址:https://www.cnblogs.com/hbyer/p/9839604.html
Copyright © 2011-2022 走看看