AcWing 337. 扑克牌

大型补档计划

题目链接

把状态实质相同的划分为一类...

发现花色、具体牌值的多少均不影响方案,考虑等效转化题目。

\(f[A][B][C][D][k]\) A 个 1 张相同,B 个 2 张相同,C 个 3张相同,D个 4张相同的牌,上一个放的牌现在有 \(k\) 张相同牌值的牌,排成的方案
状态转移就是考虑下一个放啥
\((true) = 1 (false) = 0;\)
考虑放 A 类
\(f[A - (k == 0)][B][C][D][0]\)
考虑放 B 类
\(2 * (B - (k == 1)) * f[A + 1][B - 1][C][D][1]\)
考虑放 C 类
\(3 * (C - (k == 2)) * f[A][B + 1][C - 1][C][D][2]\)
考虑放 D 类
\(4 * (D - (k == 3)) * f[A][B][C + 1][D - 1][C][D][3]\)

初始 \(f[0][0][0][0][k] = 1;\)

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef unsigned long long LL;
const int N = 14;
LL f[N][N][N][N][5];
int n, cnt[N], tot[5];
LL dp(int A, int B, int C, int D, int k) {
	if (f[A][B][C][D][k]) return f[A][B][C][D][k];
	if (!A && !B && !C && !D) return 1;
	LL &v = f[A][B][C][D][k] = 0;
	if (A) v += (A - (k == 1)) * dp(A - 1, B, C, D, 0);
	if (B) v += 2 * (B - (k == 2)) * dp(A + 1, B - 1, C, D, 1);
	if (C) v += 3 * (C - (k == 3)) * dp(A, B + 1, C - 1, D, 2);
	if (D) v += 4 * (D - (k == 4)) * dp(A, B, C + 1, D - 1, 3);
	return v;

}
int inline get(char c) {
	if (c == 'T') return 10;
	else if(c == 'J') return 11;
	else if(c == 'Q') return 12;
	else if(c == 'K') return 13;
	else if(c == 'A') return 1;
	else return c - '0';
}
int main() {
	int T; scanf("%d", &T);
	for (int Case = 1; Case <= T; Case++) {
		memset(cnt, 0, sizeof cnt);
		tot[0] = tot[1] = tot[2] = tot[3] = tot[4] = 0;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) {
			char s[3]; scanf("%s", s);
			cnt[get(s[0])]++;
		}
		for (int i = 1; i <= 13; i++) tot[cnt[i]]++;
		printf("Case #%d: %llu\n", Case, dp(tot[1], tot[2], tot[3], tot[4], 0));
	}
	return 0;
}
posted @ 2020-02-28 22:12  DMoRanSky  阅读(172)  评论(0编辑  收藏  举报