• BZOJ4197 [Noi2015]寿司晚宴 【状压dp】


    题目链接

    BZOJ4197

    题解

    两个人选的数都互质,意味着两个人选择了没有交集的质因子集合
    容易想到将两个人所选的质因子集合作为状态(dp)

    (n)以内质数很多,但容易发现(sqrt{n} approx 22.3),这里边的质数只有(8)个,而大于(sqrt{n})的质因子只会出现一次,可以特殊讨论
    我们先将所有数按最大质因子排序,如果最大质因子在那(8)个质数里边,就记为(1)
    我们设(f[i][s1][s2])表示选了前(i)个数,两人的质因子集合分别为(s1)(s2)的方案数
    那么显然

    [ans = sumlimits_{s1 cap s2 = emptyset} f[n][s1][s2] ]

    对于最大质因子不超过(sqrt{n})的那些数,我们可以枚举加入(s1)(s2)进行转移
    对于同一组最大质因数为(x)的数,我们先将(f)拷贝到(g)中,令(g[0|1][i][s1][s2])表示该最大质因数加入谁中,选了前(i)个数,质因子集合为(s1)(s2)的方案数
    求完后令(f[i][s1][s2] = g[0][i][s1][s2] + g[1][i][s1][s2] - f[i][s1][s2]),因为原来的(f)是不包含这一组数的方案,而两个(g)都包含了不包含这一组数的方案数,要减去一个

    由于空间问题,(f)(g)都要通过逆序转移压掉(i)那一维

    然后就做完了

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 505,maxm = 1 << 8,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int f[maxm][maxm],g[2][maxm][maxm];
    int n,P,a[maxn];
    int p[] = {2,3,5,7,11,13,17,19};
    struct node{
    	int x,p;
    }e[maxn];
    inline bool operator <(const node& a,const node& b){
    	return a.p < b.p;
    }
    int getp(int x){
    	for (int i = 0; i < 8; i++)
    		if (x % p[i] == 0) while (x % p[i] == 0) x /= p[i];
    	return x;
    }
    void init(){
    	for (int i = 2; i <= n; i++)
    		for (int k = 0; k < 8; k++)
    			if (i % p[k] == 0)
    				a[i] |= (1 << k);
    }
    int main(){
    	n = read(); P = read(); init();
    	for (int i = 2; i <= n; i++) e[i].x = i,e[i].p = getp(i);
    	sort(e + 2,e + 1 + n);
    	f[0][0] = 1;
    	for (int i = 2; i <= n; i++){
    		int x = e[i].x,s = a[x];
    		if (e[i].p == 1){
    			for (int j = maxm - 1; ~j; j--){
    				for (int k = maxm - 1; ~k; k--){
    					int t = f[j][k];
    					f[j][k | s] = (f[j][k | s] + t) % P;
    					f[j | s][k] = (f[j | s][k] + t) % P;
    				}
    			}
    		}
    		else {
    			for (int j = 0; j < maxm; j++)
    				for (int k = 0; k < maxm; k++)
    					g[0][j][k] = g[1][j][k] = f[j][k];
    			int nxt = i;
    			while (nxt < n && e[nxt + 1].p == e[i].p) nxt++;
    			for (int l = 0; l <= nxt - i; l++){
    				x = e[l + i].x,s = a[x];
    				for (int j = maxm - 1; ~j; j--){
    					for (int k = maxm - 1; ~k; k--){
    						g[0][j | s][k] = (g[0][j | s][k] + g[0][j][k]) % P;
    						g[1][j][k | s] = (g[1][j][k | s] + g[1][j][k]) % P;
    					}
    				}
    			}
    			i = nxt;
    			for (int j = 0; j < maxm; j++)
    				for (int k = 0; k < maxm; k++)
    					f[j][k] = (((g[1][j][k] + g[0][j][k]) % P - f[j][k]) % P + P) % P;
    		}
    	}
    	int ans = 0;
    	for (int j = 0; j < maxm; j++)
    		for (int k = 0; k < maxm; k++)
    			if (!(j & k)) ans = (ans + f[j][k]) % P;
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    cookie,请求报文,
    ser,ver
    关于 通知的 死循环,
    这读取的好蛋疼,为什么一写 一读就有问题了,不一致了,
    缓存小姐 挡拆,网络请求 不同步 惹的祸,
    viewdidload ,viewwillappear,
    提示输入 用户名 ,密码,--》转
    前端面试
    npm与cnpm
    vue与node和npm关系
  • 原文地址:https://www.cnblogs.com/Mychael/p/9157134.html
Copyright © 2020-2023  润新知