zoukankan      html  css  js  c++  java
  • [BZOJ] 1004 [HNOI2008]Cards

    题意

    (r,b,g)三种卡牌,各有各的张数,卡牌排列的不同方案数。
    两种方案相同当且仅当一种方案经过(m)个置换的其中某种置换可以变成另一种。
    保证(m)个个置换任意组合都可由其中一个代替,并且保证对于每一种置换都存在另外的置换使得它能回到原先的状态。

    题解

    第一次做置换的题目
    根据

    保证(m)个个置换任意组合都可由其中一个代替,并且保证对于每一种置换都存在另外的置换使得它能回到原先的状态。

    可知,这(m)个置换如果加上一个单位元,能够构成一个置换群。
    根据(Burnside)引理,对于一个置换群,本质不同的染色方案数为:(frac{sum 置换的不动点数量}{置换个数})

    至于一个置换的不动点数量,需要我们利用DP去计算。
    对于一个置换,我们可以把它分解成若干个循环置换,对于循环置换里面的每一个元素必须颜色相同。

    (f[i][j][k])表示三种颜色使用了i, j, k的方案数。
    这样(f[i][j][k] = f[i - sz][j][k] + f[i][j - sz][k] + f[i][j][k - sz])
    一个循环节只能取一次,所以是个01背包,要倒序循环。

    注意这里其实不是严格的置换群,因为群是一个集合,所以群里面的元素不能重复,要注意在读入时去重,不然会被luogu老哥的hack数据叉。

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <map>
    #define int long long
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    
    using namespace std;
    
    int read(){
    	char c; int num, f = 1;
    	while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
    	while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
    	return f * num;
    }
    const int N = 69;
    int r, g, b, n, m, p, tot;
    int tr[N][N], f[N][N][N], len[N], vis[N];
    //len[i]表示第i个循环置换的长度
    void up(int &x, int y) { x = (x + y) % p; }
    int cal(int *tr) {
    	tot = 0;
    	for(int i = 0; i <= r; i++) for(int j = 0; j <= b; j++) for(int k = 0; k <= g; k++) f[i][j][k] = 0;
    	for(int i = 1; i <= n; i++) vis[i] = 0;
    	for(int i = 1; i <= n; i++) if(!vis[i]){
    		int now = i, l = 0;
    		while(!vis[now]) {
    			vis[now] = 1;
    			l++;
    			now = tr[now];
    		}
    		len[++tot] = l;
    	}
    	f[0][0][0] = 1;
    	for(int i = 1; i <= tot; i++) for(int nr = r; ~nr; nr--) for(int nb = b; ~nb; nb--) for(int ng = g; ~ng; ng--){
    		if(nr >= len[i]) up(f[nr][nb][ng], f[nr - len[i]][nb][ng]);
    		if(nb >= len[i]) up(f[nr][nb][ng], f[nr][nb - len[i]][ng]);
    		if(ng >= len[i]) up(f[nr][nb][ng], f[nr][nb][ng - len[i]]);
    	}
    	return f[r][b][g];
    }
    int Pow(int a, int x) {
    	int ans = 1;
    	for( ; x; a = 1ll * a * a % p, x >>= 1)
    		if(x & 1)
    			ans = 1ll * ans * a % p;
    	return ans % p;
    }
    signed main()
    {
    	int ans = 0, vis[N] = {0}, cnt;
    	r = read(); b = read(); g = read(); n = r + b + g;
    	m = read(); p = read();
    	for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) tr[i][j] = read();	
    	m++;	
    	for(int i = 1; i <= n; i++) tr[m][i] = i;
    	cnt = m;
    	for(int i = 1; i <= m; i++) if(!vis[i]){
    		up(ans, cal(tr[i]));
    		for(int j = i + 1; j <= m; j++) if(!vis[j]){
    			int f = 1;
    			for(int k = 1; k <= n; k++) {
    				if(tr[i][k] != tr[j][k]) {
    					f = 0;
    					break;
    				}
    			}
    			if(f) {
    				vis[j] = 1;
    				cnt--;
    			}
     		}
    	}
    	
    	printf("%lld
    ", (1ll * ans * Pow(cnt, p - 2) % p));
    	return 0;
    }
    
  • 相关阅读:
    高德地图js开发,给城市某个区添加颜色
    threejs 实现易拉罐换肤功能
    React 跨页面保留前一页状态的一种实现方法
    nginx 解决客户端跟服务跨域问题
    React图片预览组件,支持缩放、旋转、上一张下一张功能
    h5 高德地图开发 谷歌浏览器定位失败解决方案
    echarts点击省份显示对应的省份
    sec:authorize 标签 通过不通过权限例子
    择左边多选框的值移动到右边多选框
    更改css element.style
  • 原文地址:https://www.cnblogs.com/onglublog/p/14477831.html
Copyright © 2011-2022 走看看