Bzoj4197: [Noi2015]寿司晚宴

来源:互联网 发布:11选5前三破解算法 编辑:程序博客网 时间:2024/03/29 19:03

原题网址:http://www.lydsy.com/JudgeOnline/problem.php?id=4197
这和今年THUSC的一题有点像,都是将根号以内的质数作状态。
首先每个质数都只能在一边出现一次,考虑状压,把包含质数的二进制压成状态,两边质数不能有交集,每次一个数放进来,枚举放左边,放右边和不放。但n以内质数有95个,考虑一个数大于n的因数不超过一个,所以可以说是这个数的特征,我们按这个特征分组,一个组里的数只能全被分到一边或两边都没有,那么这个质数就不要放到状态里了,直接看成类似分组背包就行了。用f[S][S]表示左边人状态是S,右边人状态是S的方案数,g[0][S][S]g[1][S][S]分别表示当前这一组只能左边人(右边人)取的方案数,每次一组结束要合并一下答案,然后在给下一组开始分配一下答案,合并答案的时候要注意因为这一组两个人都没取在g[0]g[1]里都被算了,所以要减去一份,减去对应的f即可。还有没有大因数的就没有限制,每个单独都能看成一组。
已经加了枚举子集的小小优化,但跑下来时间还是没达到bzoj平均水平,不过是1A,开心。(再也不会忘记+P再取模啦)

#include<bits/stdc++.h>typedef long long ll;const int N = 505;const int all = 1 << 8;const int p[8] = {2,3,5,7,11,13,17,19};struct rec{    int s,b;}a[N];int n,P;ll f[all][all],g[2][all][all],ans;bool cmp(const rec &a, const rec &b){    return a.b > b.b;}int main(){    scanf("%d%d",&n,&P);    for (int i=1; i<n; i++){        int temp = i + 1;        for (int j=0; j<8; j++){            a[i].s = a[i].s * 2 + (temp % p[j] == 0);            while (temp % p[j] == 0) temp /= p[j];          }        a[i].b = temp;    }    n--;    std::sort(a+1,a+n+1,cmp);    g[0][0][0] = 1;    g[1][0][0] = 1;    f[0][0] = 1;    for (int i=1; i<=n; i++){        if (i == 1 || a[i].b != a[i-1].b || a[i].b == 1)            for (int S=0; S<all; S++)                for (int _S=0; _S<all; _S++)                    f[S][_S] = (g[0][S][_S] + g[1][S][_S] - f[S][_S]) % P,                    g[0][S][_S] = g[1][S][_S] = f[S][_S];        int _C = (all - 1) ^ a[i].s;        for (int _S = _C; _S>=0; _S = (_S - 1) & _C){            int C = (all - 1) ^ _S;            for (int S = C; S>=0; S = (S - 1) & C){                g[0][S | a[i].s][_S] = (g[0][S | a[i].s][_S] + g[0][S][_S]) % P;                g[1][_S][S | a[i].s] = (g[1][_S][S | a[i].s] + g[1][_S][S]) % P;                if (!S) break;            }            if (!_S) break;        }    }    for (int S=0; S<all; S++)        for (int _S=0; _S<all; _S++)            ans += g[0][S][_S] + g[1][S][_S] - f[S][_S];    printf("%lld\n",(ans % P + P) % P);    return 0;}