Caddi Programming Contest 2021(AtCoder Beginner Contest 193)-D - Poker-题解


题目大意

有1~9的牌各K张,每人分5张。
得分规则是 ∑ i = 1 9 i × 1 0 c i \displaystyle \sum_{i=1}^9 i \times 10^{c_i} i=19i×10ci,其中 C i C_i Ci是这个人有牌 i i i的张数。
当每人发了4张牌时,问第一个人获胜的概率。


解题思路

∑ i = 1 9 i × 1 0 c i \displaystyle \sum_{i=1}^9 i \times 10^{c_i} i=19i×10ci理解了一切就好说了。
这句话的意思是假如有4张2,那么就获得2 * 10000(4个0)分。1张3,获得3 * 10(1个0)分。0张5,就获得5 * 1(0个0)分。

我们可以把每个人获得牌的情况枚举,计算获胜的情况占总情况的比例。
第一个人最后一张是1,第二个人最后一张是2,共9种情况;
第一个人最后一张是5,第二个人最后一张是6,共18种情况;
… …(纯属虚构)
需枚举第一个人1 ~ 9,第二个人1 ~ 9,共81次。

假如有牌堆里还剩下3张2,9张1,考虑第一个人得到2,第二个人得到1时,第一个人共有 A 3 1 = 3 A^{1}_3=3 A31=3种情况,第二个人共有 A 9 1 = 9 A^{1}_9=9 A91=9种情况,一共有 3 ∗ 9 = 27 3*9=27 39=27种情况。
假如有牌堆里还剩下9张1,考虑第一个人得到1,第二个人也得到1时,一共有 A 9 2 = 72 A^{2}_9=72 A92=72种情况。
而不管怎样,总情况就是 A 剩 余 张 数 2 A^{2}_{剩余张数} A2


AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;

ll getScore(ll s[]) //计算总得分
{
    
    
    ll ans=0;
    for(ll i=1;i<10;i++)
    {
    
    
        ans+=i*pow(10,s[i]);
    }
    return ans;
}
int main()
{
    
    
    ll k;
    cin >> k; 
    char s[10], t[10];
    cin >> s >> t;
    ll shengyu[10] = {
    
    0}; //shengyu[i]表示i还剩多少张
    for (ll i = 1; i < 10; i++)
        shengyu[i] = k; //没有发牌时1~9都各剩k张
    ll suma[10] = {
    
    0}; //s中有每种牌各多少
    ll sumb[10] = {
    
    0}; //t中有每种牌各多少
    for (ll i = 0; i < 4; i++) //已经发下来的前4张
    {
    
    
        shengyu[s[i] - '0']--; //第一个人起到了s[i],s[i]的剩余张数减1
        shengyu[t[i] - '0']--; //第一个人起到了t[i],t[i]的剩余张数减1
        suma[s[i]-'0']++;//第一个人起到了s[i],第一个人的s[i]的张数加1
        sumb[t[i]-'0']++;//第一个人起到了t[i],第一个人的t[i]的张数加1
    }
    ll canWin=0; //所有可以获胜的情况
    for (ll i = 1; i <= 9; i++) //第一个人起到了i
    {
    
    
        for (ll j = 1; j <= 9; j++) //第二个人起到了j
        {
    
    
            bool sfbx=false; //这种情况是否不行(当剩余牌没有i和j时,这种情况不行)
            if(shengyu[i]<=0)sfbx=true; //没i了
            if(shengyu[j]<=0)sfbx=true; //没j了
            if(i==j && shengyu[i]<=1)sfbx=true; //没有两张i
            suma[i]++; //第一个人起到了i
            sumb[j]++; //第二个人起到了j
            if(!sfbx) //不是不行
            {
    
    
                ll sa=getScore(suma); //第一个人的得分
                ll sb=getScore(sumb); //第二个人的得分
                if(sa>sb) //第一个人获胜
                {
    
    
                    if(i==j) //两人最后一张牌相同
                        canWin += shengyu[i] * (shengyu[i]-  1);
                    else
                        canWin += shengyu[i] * shengyu[j];
                }
            }
            suma[i]--; //这种情况考虑结束,放回最后一张牌
            sumb[j]--;
        }
    }
    ll shengyuAll = k*9-8; //所有剩余的牌
    ll canAll = shengyuAll*(shengyuAll-1); //所有可能的情况(对应A shengyuAll 2)
    double ans = 1. * canWin / canAll;
    printf("%.15lf\n", ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Tisfy/article/details/114196389
今日推荐