其他分享
首页 > 其他分享> > 2022牛客暑期多校第一场 I. Chiitoitsu

2022牛客暑期多校第一场 I. Chiitoitsu

作者:互联网

2022牛客暑期多校第一场 I. Chiitoitsu

题意

日本麻将共有 \(34\) 种牌,每种牌各 \(4\) 张,共 \(136\) 张牌,给定一开始手上的 \(13\) 张牌,剩下的 \(123\) 张牌在牌堆中,每次随机从牌堆摸 \(1\) 张,摸完后若手上的 \(14\) 张牌是 \(7\) 对互不相同的对子,则游戏结束,否则需要在 \(14\) 张牌中选择 \(1\) 张丢弃(不放回牌堆,意味着牌堆中牌的数量会随着摸牌次数逐渐减少),继续上述过程,直到凑满 \(7\) 对互不相同的对子。

保证给定的一开始手上的 \(13\) 张牌,不会存在 \(1\) 种牌超过 \(3\) 张。

问,最优策略下的期望摸牌次数。

分析

容易有一个直观的想法:

已有的对子不丢弃。

若对于抽到的牌的种类已经在手里的牌中形成对子,则丢弃抽到的牌。

若抽到的牌在手上无法和已有的牌形成对子,丢弃最不可能在牌堆中再次抽到的那种牌。

若抽到的牌能和手上的某张牌形成对子,则配对,丢弃最不可能在牌堆中抽到的那种牌。

根据这个想法,对于一开始手上的每种牌不是 \(2\) 张,就是 \(1\) 张,牌堆里的每种牌只可能是 \(2\) 张、\(3\) 张或 \(4\) 张。

一开始,抽到剩余 \(3\) 张的必成对,抽到剩余 \(4\) 张的必不成对,剩下 \(3\) 张牌,此时丢掉其他单牌和丢掉抽到的这张单牌没有本质区别,都会多一种牌有 \(1\) 张是浪费掉的,且剩余 \(3\) 张都在牌堆里,其余都一样。之后,根据上面直观的想法,曾经被弃掉那种牌不可能再用它来形成对子。

所以最优策略可以贪心的认为,除去手上的对子以外,根据手上的单牌去凑对子。

这个时候,对于要凑成对子但还没凑成对子的牌,在牌堆里只可能剩下 \(3\) 张。这样,期望步数就和牌的种类无关,只和手上已经凑了几对牌,以及牌堆里还剩下几张牌有关。

定义状态 \(f(i,j)\) 为抽牌之前(手上有 \(13\) 张牌),牌堆里还剩 \(i\) 张牌,手上已经凑成 \(j\) 对对子的期望步数。

显然 \(3 \leq i \leq 123, 0 \leq j \leq 6\)

由于还需要凑 \(7-j\) 对牌,这种状态之下,只有 \(3(7-j) \leq i\) 是合法状态。

由于手上有 \(13-2j\) 张单牌,这种状态之下,

当 \(3(13-2j) \geq i\) 时,接下来抽到的牌一定会和手上的牌成对。

当 \(3(13-2j) \leq i\) 时,接下来抽到的牌有 \(\frac{3(13-2j)}{i}\) 的概率和手上的牌成对,有 \(1-\frac{3(13-2j)}{i}\) 的概率不和手上的牌成对。

根据上述分析,写出状态转移及初始条件:

当 \(i>3\) 且 \(0 \leq j \leq 5\) 时

\[f(i,j)=\left\{ \begin{aligned} &\frac{3(13-2j)}{i}f(i-1,j+1)+\left(1-\frac{3(13-2j)}{i}\right)f(i-1,j)+1, &3(13-2j) \leq i \\ &f(i-1,j+1)+1, &3(13-2j) > i\\ \end{aligned} \right. \]

当 \(i>3\) 且 \(j=6\) 时

\[f(i,j)=\left(1-\frac{3(13-2j)}{i}\right)f(i-1,j)+1 \]

特别地,

\[f(3,6)=1\\ \]

于是,最后只需要统计一开始手上的对子数 \(c\),答案就是 \(f(123,c)\)

代码

#include <iostream>
#include <map>
#include <string>
using namespace std;
typedef long long Lint;
const int mod = 1e9 + 7;
inline int add(int a, int b) {
    return (a += b) < mod ? a : a - mod;
}
inline int mul(int a, int b) {
    return (Lint)a * b % mod;
}
int dp[7], inv[124];
void solve(int kase) {
    string s;
    map<string, int> num;
    cin >> s;
    for (int i = 0; i < s.size(); i += 2) {
        num[s.substr(i, 2)]++;
    }
    int c = 0;
    for (auto it : num)
        c += (it.second == 2);
    cout << "Case #" << kase << ": " << dp[c] << '\n';
}
int main() {
    inv[1] = 1;
    for (int i = 2; i <= 123; i++) {
        inv[i] = mul(mod - mod / i, inv[mod % i]);
    }
    dp[6] = 1;
    for (int i = 4; i <= 123; i++) {
        for (int j = 0; j <= 5; j++) {
            if (3 * (7 - j) > i)
                continue;
            if (3 * (13 - 2 * j) >= i) {
                dp[j] = add(dp[j + 1], 1);
            } else {
                int p = mul(3 * (13 - 2 * j), inv[i]);
                dp[j] = add(add(mul(p, dp[j + 1]), mul(add(1, mod - p), dp[j])), 1);
            }
        }
        int p = mul(i - 3, inv[i]);
        dp[6] = add(mul(p, dp[6]), 1);
    }
    int T;
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> T;
    for (int i = 1; i <= T; i++)
        solve(i);
    return 0;
}

标签:13,抽到,牛客,int,多校,张牌,Chiitoitsu,对子,2j
来源: https://www.cnblogs.com/Bamboo-Wind/p/16499831.html