zoukankan      html  css  js  c++  java
  • bzoj 1004

    Pros

    给若干个置换, 和三种颜色, 问有多少种本质不同的染色方案?

    Sol

    Burnside:

    首先由 (burnside) 引理
    $$Ans = frac{sum_{:i = 1}^{:m};f_i}{m}$$
    其中 (f_i) 表示第 (i) 个置换的不动点的个数.
    不动点的个数 就是在该置换下只有一种同构体的方案数.

    置换的循环分解:

    然后,前面 lyp 学长在这里讲,
    关于一个置换能够分解成若干个环,
    (example:)

    [egin{equation} left( egin{array}{ccccc} 1 & 2 & 3 & 4 & 5\ 3 & 2 & 5 & 1 & 4\ end{array} ight) end{equation} ]

    包含环:(1 ightarrow 3 ightarrow 5 ightarrow 4 ightarrow 1)(2 ightarrow 2)
    对于任意一个环, 作用在上面的一次置换能够让这个环上面的元素循环移位一格.

    不动点的条件

    那么要让这个环能够成为不动点的充要条件就是,每个环上的颜色都是相同的.

    然后,我们就能够 DP 了. 预处理环是学的别人的,感觉挺涨见识的.

    #include<cstdlib>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 100;
    int n,m,sr,sb,sg,p,ans;
    int f[maxn][maxn][maxn];
    int g[maxn],vis[maxn],cir[maxn];
    inline int dfs(int x){
    	return vis[x] ? 0 : (vis[x] = 1, dfs(g[x]) + 1);
    }
    inline void init(){
    	for(int i = 0; i < maxn; ++i) vis[i] = cir[i] = 0;
    	memset(f,0,sizeof(f)); ans = 0;
    }
    inline void add_mod(int &a,int b){
    	a = (a + b) % p;
    }
    inline int exgcd(int a,int b,int p){
    	return p % a ?(exgcd(b % a, a, (-p % a + a) % a) * b + p) / a : p / a; 
    }
    int main()
    {
    	freopen("card.in","r",stdin);
    	freopen("card.out","w",stdout);
    	scanf("%d %d %d %d %d
    ",&sr,&sb,&sg,&m,&p);
    	n = sr + sb + sg; m++;
    	for(int i = 1; i <= m; ++i){
    		for(int j = 1; j <= n; ++j)
    			i == m ? g[j] = j : scanf("%d",&g[j]);
    		init();
    		for(int j = 1; j <= n; ++j) if(!vis[j]) cir[++cir[0]] = dfs(j);
    		f[0][0][0] = 1;
    		for(int j = 1; j <= cir[0]; ++j)
    			for(int k = 0; k <= sr; ++k)
    				for(int l = 0; l <= sb; ++l){
    					int &F = f[j][k][l], t = n - k - l;
    					if(k >= cir[j]) add_mod(F, f[j-1][k - cir[j]][l]);
    					if(l >= cir[j]) add_mod(F, f[j-1][k][l - cir[j]]);
    					if(t >= cir[j]) add_mod(F, f[j-1][k][l]);
    				}
    		ans = (ans + f[cir[0]][sr][sb]) % p;
    	}
    	ans = ans * exgcd(m, p, 1) % p;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    有一天,我们能这样相爱吗?
    端午节来源六说
    一个ini类代替缓存使用
    创意生活可爱香皂
    漂亮的韩国发饰
    Oracle中PL/SQL单行函数和组函数详解
    真正爱你的女人是这样的
    执子之手,与子偕老。你同意么?
    男人如茶
    Oracle SQL 內置函數大全
  • 原文地址:https://www.cnblogs.com/Mr-ren/p/4297761.html
Copyright © 2011-2022 走看看