• 【BZOJ 1004】【HNOI 2008】Cards


    http://www.lydsy.com/JudgeOnline/problem.php?id=1004
    注意数据给出的m是一个没有单位元的置换群!
    用Burnside引理,然后对每个置换群dp一下就可以了。

    #include<cstdio>
    #include<bitset>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int a[63], Sr, Sb, Sg, m, p, n, ans = 0;
    
    int ipow(int w, int b) {
    	int ret = 1;
    	while (b) {
    		if (b & 1) ret = ret * w % p;
    		w = w * w % p;
    		b >>= 1;
    	}
    	return ret;
    }
    
    int f[63][63][63][63], w[63], tot;
    bitset <64> vis;
    
    int dp() {
    	vis.reset(); tot = 0;
    	for (int i = 1; i <= n; ++i)
    		if (!vis[i]) {
    			vis[i] = 1;
    			w[++tot] = 1;
    			int tmp = a[i];
    			while (!vis[tmp]) {
    				vis[tmp] = 1;
    				++w[tot];
    				tmp = a[tmp];
    			}
    		}
    	
    	for (int i = 1; i <= tot; ++i)
    		for (int R = 0; R <= Sr; ++R)
    			for (int B = 0; B <= Sb; ++B)
    				for (int G = 0; G <= Sg; ++G) {
    					f[i][R][B][G] = 0;
    					if (R >= w[i]) (f[i][R][B][G] += f[i - 1][R - w[i]][B][G]) %= p;
    					if (B >= w[i]) (f[i][R][B][G] += f[i - 1][R][B - w[i]][G]) %= p;
    					if (G >= w[i]) (f[i][R][B][G] += f[i - 1][R][B][G - w[i]]) %= p;
    				}
    	return f[tot][Sr][Sb][Sg];
    }
    
    int main() {
    	scanf("%d%d%d%d%d", &Sr, &Sb, &Sg, &m, &p);
    	n = Sr + Sb + Sg; f[0][0][0][0] = 1;
    	for (int j = 1; j <= n; ++j) a[j] = j;
    	(ans += dp()) %= p;
    	for (int i = 1; i <= m; ++i) {
    		for (int j = 1; j <= n; ++j) scanf("%d", a + j);
    		(ans += dp()) %= p;
    	}
    	printf("%d
    ", ans * ipow(m + 1, p - 2) % p);
    	return 0;
    }
    
  • 相关阅读:
    前端必备书籍
    搜索引擎的使用技巧
    PS切图
    css背景透明
    前端
    连接查询,A连B,B筛选出多条记录时,选用第一条记录
    mssql 过滤重复记录,取第一笔记录
    MongoDB 日常操作
    OEE计算
    Aspose.Cells: excel 转 pdf
  • 原文地址:https://www.cnblogs.com/abclzr/p/6430801.html
Copyright © 2020-2023  润新知