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

    $ color{#0066ff}{ 题目描述 }$

    小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.

    进一步,小春要求染出Sr张红色,Sb张蓝色,Sg张绿色.他又询问有多少种方案,Sun想了一下,又给出了正确答案. 最后小春发明了M种不同的洗牌法,这里他又问Sun有多少种不同的染色方案.两种染色方法相同当且仅当其中一种可以通过任意的洗牌法(即可以使用多种洗牌法,而每种方法可以使用多次)洗成另一种.

    Sun发现这个问题有点难度,决定交给你,答案可能很大,只要求出答案除以P的余数(P为质数).

    (color{#0066ff}{输入格式})

    第一行输入 5 个整数:Sr,Sb,Sg,m,p(m<=60,m+1<p<100)。n=Sr+Sb+Sg。接下来 m 行,每行描述一种洗牌法,每行有 n 个用空格隔开的整数 X1X2...Xn,恰为 1 到 n 的一个排列,表示使用这种洗牌法,第 i位变为原来的 Xi位的牌。输入数据保证任意多次洗牌都可用这 m种洗牌法中的一种代替,且对每种

    洗牌法,都存在一种洗牌法使得能回到原状态。

    100%数据满足 Max{Sr,Sb,Sg}<=20。

    (color{#0066ff}{输出格式})

    不同染法除以P的余数

    (color{#0066ff}{输入样例})

    1 1 1 2 7
    2 3 1
    3 1 2
    

    (color{#0066ff}{输出样例})

    2
    

    (color{#0066ff}{数据范围与提示})

    有2 种本质上不同的染色法RGB 和RBG,使用洗牌法231 一次可得GBR 和BGR,使用洗牌法312 一次 可得BRG 和GRB。

    [HNOI2008]

    (color{#0066ff}{题解})

    因为有颜色数量的限制,所以Polya就不太可行了

    没事,我们还有Burnside

    于是我们要找每个置换下不变的方案数

    不难发现,对于每个循环,循环中的颜色必须相同才行

    于是把当前置换的循环处理出来,当成物品跑01背包,就可以求出不变的方案数

    注意还有额外的一种置换是不洗牌,也就是说不变,要特殊处理

    #include<bits/stdc++.h>
    #define LL long long
    LL in() {
    	char ch; LL x = 0, f = 1;
    	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    	return x * f;
    }
    int f[50][50][50];
    bool vis[100];
    int mp[100];
    int siz[100];
    int ans;
    int a, b, c, m, mod, n;
    LL ksm(LL x, LL y) {
    	LL re = 1LL;
    	while(y) {
    		if(y & 1) re = re * x % mod;
    		x = x * x % mod;
    		y >>= 1;
    	}
    	return re;
    }
    int work(int flag) {
    	memset(f, 0, sizeof f);
    	for(int i = 1; i <= n; i++) vis[i] = 0, siz[i] = 0;
    	int num = 0;
    	if(!flag) {
    		for(int i = 1; i <= n; i++) {
    			if(vis[i]) continue;
    			num++;
    			int now = i;
    			while(!vis[now]) vis[now] = true, siz[num]++, now = mp[now];
    		}
    	}
    	else {
    		num = n;
    		for(int i = 1; i <= n; i++) siz[i] = 1;
    	}
    	f[0][0][0] = 1;
    	for(int i = 1; i <= num; i++)
    		for(int A = a; A >= 0; A--)
    			for(int B = b; B >= 0; B--)
    				for(int C = c; C >= 0; C--) {
    					if(A >= siz[i]) (f[A][B][C] += f[A - siz[i]][B][C]) %= mod;
    					if(B >= siz[i]) (f[A][B][C] += f[A][B - siz[i]][C]) %= mod;
    					if(C >= siz[i]) (f[A][B][C] += f[A][B][C - siz[i]]) %= mod;
    				}
    	return f[a][b][c];
    }
    
    int main() {
    	n = (a = in()) + (b = in()) + (c = in());
    	m = in(), mod = in();
    	for(int i = 1; i <= m; i++) {
    		for(int j = 1; j <= n; j++) mp[j] = in();
    		(ans += work(0)) %= mod;
    	}
    	(ans += work(1)) %= mod;
    	printf("%lld", 1LL * ans * ksm(m + 1, mod - 2) % mod);
    	return 0;
    }
    
  • 相关阅读:
    无限维
    黎曼流形
    why we need virtual key word
    TOJ 4119 Split Equally
    TOJ 4003 Next Permutation
    TOJ 4002 Palindrome Generator
    TOJ 2749 Absent Substrings
    TOJ 2641 Gene
    TOJ 2861 Octal Fractions
    TOJ 4394 Rebuild Road
  • 原文地址:https://www.cnblogs.com/olinr/p/10426953.html
Copyright © 2011-2022 走看看