【BZOJ1004】【HNOI2008】Cards

【题目链接】

【思路要点】

  • 题意表明,给定的洗牌方式在加上单位置换后(原本存在就不需要再加了)是一个置换群。考虑Burnside引理或Polya定理。
  • 注意到题目有颜色的使用次数的限制,因此不便使用Polya定理,考虑使用Burnside引理,求解每一个置换的本质不同的染色方案数的平均数。
  • 显然可以设计动态规划在\(O(N*R*G*B)\)的时空复杂度内求解一个置换的本质不同的染色方案数。
  • 因此,总时间复杂度为\(O(N*M*R*G*B)\),可以通过本题。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	65
#define MAXM	65
#define MAXC	25
int R, G, B, m, P, n, cnt, now;
int f[MAXM][MAXN];
bool visited[MAXN];
bool mark[MAXN][MAXC][MAXC][MAXC];
int value[MAXN][MAXC][MAXC][MAXC];
void visit(int pos) {
	if (visited[pos]) return;
	cnt++; visited[pos] = true;
	visit(f[now][pos]);
}
void clean(int pos) {
	if (!visited[pos]) return;
	visited[pos] = false;
	clean(f[now][pos]);
}
int get(int pos, int R, int G, int B) {
	if (pos == 0) return 1;
	if (visited[pos]) return get(pos - 1, R, G, B);
	if (mark[pos][R][G][B]) return value[pos][R][G][B];
	cnt = 0; value[pos][R][G][B] = 0;
	visit(pos);
	int tmp = cnt;
	if (R >= tmp) value[pos][R][G][B] += get(pos - 1, R - tmp, G, B);
	if (G >= tmp) value[pos][R][G][B] += get(pos - 1, R, G - tmp, B);
	if (B >= tmp) value[pos][R][G][B] += get(pos - 1, R, G, B - tmp);
	clean(pos);
	value[pos][R][G][B] %= P;
	mark[pos][R][G][B] = true;
	return value[pos][R][G][B];
}
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return tmp * tmp % P;
	else return tmp * tmp % P * x % P;
}
int main() {
	scanf("%d%d%d%d%d", &R, &G, &B, &m, &P);
	n = R + G + B;
	bool flg = false;
	for (int i = 1; i <= m; i++) {
		bool now = true;
		for (int j = 1; j <= n; j++) {
			scanf("%d", &f[i][j]);
			now &= f[i][j] == j;
		}
		flg |= now;
	}
	if (!flg) {
		m++;
		for (int i = 1; i <= n; i++)
			f[m][i] = i;
	}
	int ans = 0;
	for (int i = 1; i <= m; i++) {
		now = i;
		memset(mark, false, sizeof(mark));
		ans += get(n, R, G, B);
		ans %= P;
	}
	printf("%d\n", ans * power(m, P - 2) % P);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值