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

105 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

@TOC


题目大意

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


解题思路

i=19i×10ci\displaystyle \sum_{i=1}^9 i \times 10^{c_i}理解了一切就好说了。 这句话的意思是假如有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时,第一个人共有A31=3A^{1}_3=3种情况,第二个人共有A91=9A^{1}_9=9种情况,一共有39=273*9=27种情况。 假如有牌堆里还剩下9张1,考虑第一个人得到1,第二个人也得到1时,一共有A92=72A^{2}_9=72种情况。 而不管怎样,总情况就是A剩余张数2A^{2}_{剩余张数}


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;
}

同步发文于我的CSDN