AcWing - 337 - 扑克牌 = dp + 组合数学

https://www.acwing.com/problem/content/description/339/

感觉非常沙雕的一个东西。

首先设状态的时候要按张数来设,这样空间复杂度比较小。因为本身就和花色和面值没有什么关系的。

然后在预处理的时候就直接考虑花色的影响,就是乘上一个排列数。

记得要容斥一下,不然答案很有问题。

不知道为什么我的unsigned long long用不了(原因是因为减法a-1>=0溢出了),只好搞个__int128来表示模数,真是麻烦。

#include
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
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);
    }
}

你可能感兴趣的:(AcWing - 337 - 扑克牌 = dp + 组合数学)