https://www.acwing.com/problem/content/description/339/
感觉非常沙雕的一个东西。
首先设状态的时候要按张数来设,这样空间复杂度比较小。因为本身就和花色和面值没有什么关系的。
然后在预处理的时候就直接考虑花色的影响,就是乘上一个排列数。
记得要容斥一下,不然答案很有问题。
不知道为什么我的unsigned long long用不了(原因是因为减法a-1>=0溢出了),只好搞个__int128来表示模数,真是麻烦。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 ull;
ull dp[20][20][20][20] = {};
ull TWO = 2, THREE = 3, FOUR = 4, SIX = 6, MOD = 1;
const ull CEIL = 13;
string s;
ull mut(ull a, ull b) {
ull res = 0;
while(b) {
if(b & 1)
res = (res + a) % MOD;
a = (a + a) % MOD;
b >>= 1;
}
return res;
}
void init() {
MOD <<= 64;
for(ull d = 0; d <= CEIL; ++d) {
for(ull c = 0; c <= CEIL; ++c) {
for(ull b = 0; b <= CEIL; ++b) {
for(ull a = 0; a <= CEIL; ++a) {
if(a == 0 && b == 0 && c == 0 && d == 0) {
dp[0][0][0][0] = 1llu;
continue;
}
if(a - 1 >= 0)
dp[a][b][c][d] += mut(dp[a - 1][b][c][d], a);
if(b - 1 >= 0) {
dp[a][b][c][d] += mut(mut(dp[a + 1][b - 1][c][d], TWO), b);
dp[a][b][c][d] -= mut(mut(dp[a][b - 1][c][d], TWO), b);
}
if(c - 1 >= 0) {
dp[a][b][c][d] += mut(mut(dp[a][b + 1][c - 1][d], THREE), c);
dp[a][b][c][d] -= mut(mut(mut(dp[a + 1][b][c - 1][d], THREE), TWO), c);
dp[a][b][c][d] += mut(mut(mut(dp[a][b][c - 1][d], THREE), TWO), c);
}
if(d - 1 >= 0) {
dp[a][b][c][d] += mut(mut(dp[a][b][c + 1][d - 1], FOUR), d);
dp[a][b][c][d] -= mut(mut(mut(dp[a][b + 1][c][d - 1], FOUR), THREE), d);
dp[a][b][c][d] += mut(mut(mut(mut(dp[a + 1][b][c][d - 1], FOUR), THREE), TWO), d);
dp[a][b][c][d] -= mut(mut(mut(mut(dp[a][b][c][d - 1], FOUR), THREE), TWO), d);
}
dp[a][b][c][d] = (dp[a][b][c][d] % MOD + MOD) % MOD;
}
}
}
}
}
void write(ull ans) {
if(ans >= 10) {
write(ans / 10);
}
putchar(ans % 10 + '0');
}
int cnt[14] = {};
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
init();
int t;
cin >> t;
for(int ti = 1; ti <= t; ++ti) {
int n;
cin >> n;
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= n; ++i) {
cin >> s;
if(s[0] == 'T') {
cnt[10]++;
} else if(s[0] == 'A') {
cnt[1]++;
} else if(s[0] == 'J') {
cnt[11]++;
} else if(s[0] == 'Q') {
cnt[12]++;
} else if(s[0] == 'K') {
cnt[13]++;
} else {
cnt[s[0] - '0']++;
}
}
ull cnt1 = 0, cnt2 = 0, cnt3 = 0, cnt4 = 0;
for(int i = 1; i <= 13; ++i) {
if(cnt[i] == 1)
cnt1++;
else if(cnt[i] == 2)
cnt2++;
else if(cnt[i] == 3)
cnt3++;
else if(cnt[i] == 4)
cnt4++;
}
ull tmp = dp[cnt1][cnt2][cnt3][cnt4];
cout << "Case #" << ti << ": ";
write(tmp);
cout << "\n";
}
}
所以就印证了一句话,没事就不需要用unsigned,不然出事。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ull dp[20][20][20][20] = {};
ull TWO = 2, THREE = 3, FOUR = 4, SIX = 6;
const int CEIL = 13;
string s;
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
for(int d = 0; d <= CEIL; ++d) {
for(int c = 0; c <= CEIL; ++c) {
for(int b = 0; b <= CEIL; ++b) {
for(int a = 0; a <= CEIL; ++a) {
if(a == 0 && b == 0 && c == 0 && d == 0) {
dp[0][0][0][0] = 1llu;
continue;
}
if(a - 1 >= 0)
dp[a][b][c][d] += dp[a - 1][b][c][d] * a;
if(b - 1 >= 0) {
dp[a][b][c][d] += dp[a + 1][b - 1][c][d] * TWO * b;
dp[a][b][c][d] -= dp[a][b - 1][c][d] * TWO * b;
}
if(c - 1 >= 0) {
dp[a][b][c][d] += dp[a][b + 1][c - 1][d] * THREE * c;
dp[a][b][c][d] -= dp[a + 1][b][c - 1][d] * THREE * TWO * c;
dp[a][b][c][d] += dp[a][b][c - 1][d] * THREE * TWO * c;
}
if(d - 1 >= 0) {
dp[a][b][c][d] += dp[a][b][c + 1][d - 1] * FOUR * d;
dp[a][b][c][d] -= dp[a][b + 1][c][d - 1] * FOUR * THREE * d;
dp[a][b][c][d] += dp[a + 1][b][c][d - 1] * FOUR * THREE * TWO * d;
dp[a][b][c][d] -= dp[a][b][c][d - 1] * FOUR * THREE * TWO * d;
}
}
}
}
}
int t;
scanf("%d", &t);
for(int ti = 1; ti <= t; ++ti) {
int n;
scanf("%d", &n);
int cnt[14] = {};
for(int i = 1; i <= n; ++i) {
cin >> s;
if(s[0] == 'T') {
cnt[10]++;
} else if(s[0] == 'A') {
cnt[1]++;
} else if(s[0] == 'J') {
cnt[11]++;
} else if(s[0] == 'Q') {
cnt[12]++;
} else if(s[0] == 'K') {
cnt[13]++;
} else {
cnt[s[0] - '0']++;
}
}
ull cnt1 = 0, cnt2 = 0, cnt3 = 0, cnt4 = 0;
for(int i = 1; i <= 13; ++i) {
if(cnt[i] == 1)
cnt1++;
else if(cnt[i] == 2)
cnt2++;
else if(cnt[i] == 3)
cnt3++;
else if(cnt[i] == 4)
cnt4++;
}
ull tmp = dp[cnt1][cnt2][cnt3][cnt4];
printf("Case #%d: %llu\n", ti, tmp);
}
}