2022牛客暑期多校训练营1 I Chiitoitsu

1 篇文章 0 订阅

2022牛客暑期多校训练营1 I Chiitoitsu

纯属个人训练记录,方便以后复题用
以下均代表个人对题解的理解

Chiitoitsu

题意:(借用自牛客题解)在这里插入图片描述
题解:实因为每种牌数量都是4张,并且初始牌中不会出现超过三张一样的牌,所以我们可以把牌分成两类,一类是已经成队了的,另一类是单牌,显然已经成队的不会再进行替换,可以当作没有,而单牌因为我知道已经打出了哪些牌,所有我每次总可以使得手牌中的单牌都是之前还没有出现过的单牌,即牌堆中还有 3 3 3张一样的,这样我们可以预处理一下,用 d p [ i ] [ j ] dp[i][j] dp[i][j]表示手上还有 i i i张单排,牌堆还有 j j j张牌时还需要摸牌次数的期望值,那么我根据当前摸的牌是否可以和我手上的单牌配对可分为两种:
1.可以和当前手上单牌配对,那么配对后需要再扔掉一张单牌,当前单牌数减少二(一张被配对了,一张被扔掉了),牌堆内牌数减一,概率为 3 ∗ i j \frac{3*i}{j} j3i
2.不可以和当前手上单牌配对,那么我必定扔掉(因为手上原本的单牌一定有三张还没出现的在牌堆,他们遇到能匹配的概率一定是等于或优于当前摸到的单牌),那么当前单牌数不变,牌堆内牌数减一,概率为 j − 3 ∗ i j \frac{j-3*i}{j} jj3i

状态转移方程为: d p [ i ] [ j ] = 1 + 3 ∗ i j ∗ d p [ i − 2 ] [ j − 1 ] + j − 3 ∗ i j ∗ d p [ i ] [ j − 1 ] dp[i][j]=1+\frac{3*i}{j}*dp[i-2][j-1]+\frac{j-3*i}{j}*dp[i][j-1] dp[i][j]=1+j3idp[i2][j1]+jj3idp[i][j1],
注意当 i i i为1时: d p [ 1 ] [ j ] = 1 + 3 j ∗ 0 + j − 3 j ∗ d p [ i ] [ j − 1 ] = 1 + j − 3 j ∗ d p [ i ] [ j − 1 ] dp[1][j]=1+\frac{3}{j}*0+\frac{j-3}{j}*dp[i][j-1]=1+\frac{j-3}{j}*dp[i][j-1] dp[1][j]=1+j30+jj3dp[i][j1]=1+jj3dp[i][j1]
预处理出 d p dp dp数组后,每次输入判断下有多少张单牌即可
细节和不懂可以看代码

ll mi(ll a,ll b){
	ll res=1;
	while(b){
		if(b%2){
			res=res*a%mod;
		}
		a=a*a%mod;
		b/=2;
	}
	return res;
}
map<string,bool>mp;
ll dp[20][200];//已经配对了i副,还有j张没摸时还要摸牌次数的期望
int main(){
/*cout<<setiosflags(ios::fixed)<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(不含整数部分)*/
/*cout<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(含整数部分)*/
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//同步流
	ll sum=34*4-13;
	for(ll i=3;i<=sum;i++){
		dp[1][i]=(1+(((i-3)*mi(i,mod-2)%mod)*dp[1][i-1]%mod))%mod;
	} 
	for(ll i=3;i<=13;i+=2){
		for(ll j=3;j<=sum;j++){
			dp[i][j]=(1+(((i*3)*mi(j,mod-2)%mod)*dp[i-2][j-1]%mod)+(((j-i*3)*mi(j,mod-2)%mod)*dp[i][j-1]%mod))%mod;
		}
	}
	int t;
	cin>>t;
	for(int times=1;times<=t;times++){
		string s;
		cin>>s;
		string ss;
		int num=0;
		mp.clear();
		for(int i=1;i<s.length();i+=2){
			ss="";
			ss+=s[i-1];
			ss+=s[i];
			if(mp.count(ss)){
				num--;
			}
			else{
				mp[ss]=1;
				num++;
			}
		}
		cout<<"Case #"<<times<<": "<<dp[num][sum]<<endl;
	}
	return 0;
}
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值