牛客暑期多校训练1

I.Chiitoitsu

  • 一个概率dp
  • 题目是让求摸到麻将中七个对子胡牌的期望局数(11,22,33诸如此类)
  • 这个麻将有34种不同类型的牌,每一种类型的牌具有4张,初始时手中有13张牌,相同的牌至多有两张,每一局会在剩下的牌中摸一张,选择要或不要。要的话就需要打出手中13张牌中的一张,不要的话这张牌废弃,并且不会再被摸到
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int t,s0,num[15][5];
int tmp=0,k=0;
ll dp[130][15];//dp[i][j]为剩余i张牌,手里有j张单牌时,还需要多少轮才能胡牌的期望局数
//对分数取模用逆元快速幂
ll ksm(ll a,ll b)//O(logn)
{
	ll res=1;
	while(b)
	{
		if(b&1) res=a*res%mod;
		a=a*a%mod;
		b>>=1;  
	}
	return res;
}
//由于是对除法取模,容易出现精度问题,所以可以通过使用逆元把除法取余转化为乘法取余。
//使用费马小定理求逆元,(a/b)%p,b^(-1)=b^(p-2);
ll inv(ll x)
{
	return ksm(x,mod-2);
}
void init()
{
	for(int i=1;i<=123;i++){
		ll v=inv(i);
		//cout << v << endl;
		for(int j=0;j<=13;j++){
			if(j==1) dp[i][j]=((i-3)*v%mod*(dp[i-1][1]+1)%mod+3*v%mod)%mod;
            //手里还剩一张单牌时,情况有两种,一种是没有抽到能构成对子的单牌,概率为(i-3)/i,状态为dp[i-1][1];第二种是抽到了,此时的概率为3/i,最后再加上当前局数1;
			else dp[i][j]=((i-3*j)*v%mod*(dp[i-1][j]+1)%mod+(dp[i-1][j-2]+1)*3*j%mod*v%mod)%mod;
            //手里的单牌数大于1时,如果抽出来的是可以组成对子的单牌,概率为3*j/i,状态为dp[i-1][j-2];如果抽出来的是一张不能构成对子的单牌,概率为(i-3j)/i,状态为dp[i-i][j];
		}
	}
	return;
}
int main() {
    cin>>t;
    getchar();
    init();
    string s;
    while(t--){
        getline(cin,s);
        memset(num,0,sizeof(num));
        k=0;
        s0=0;
        for(int i=0;i<26;i+=2){
            int x=s[i]-'0',y;
            if(s[i+1]=='m') y=1;
            else if(s[i+1]=='p') y=2;
            else if(s[i+1]=='s') y=3;
            else y=4;
            num[x][y]++;
            if(num[x][y]==2) k++;//原始对子的个数
        }
        s0=13-2*k;
        //cout<<s0<<endl;
        printf("Case #%d: %lld\n",++tmp,dp[123][s0]);//dp[4*34-13][s],s为手里单牌的数量
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值