【题解】【CCF】202109-4 收集卡牌

本文介绍了小林玩的一款抽卡游戏,其中涉及到不同概率的卡牌和硬币兑换机制。通过计算期望抽卡次数,探讨了最优的抽卡策略。文章通过样例解释了如何计算期望值,并提供了程序解题思路,涉及动态规划和概率计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

计算机软件能力认证考试系统

题目描述

题目描述

小林在玩一个抽卡游戏,其中有 n 种不同的卡牌,编号为 1 到 n。每一次抽卡,她获得第 i 种卡牌的概率为 pi。如果这张卡牌之前已经获得过了,就会转化为一枚硬币。可以用 k 枚硬币交换一张没有获得过的卡。

小林会一直抽卡,直至集齐了所有种类的卡牌为止,求她的期望抽卡次数。如果你给出的答案与标准答案的绝对误差不超过 10−4,则视为正确。

提示:聪明的小林会把硬币攒在手里,等到通过兑换就可以获得剩余所有卡牌时,一次性兑换并停止抽卡。

输入格式

从标准输入读入数据。

输入共两行。第一行包含两个用空格分隔的正整数 n,k,第二行给出 p1,p2,…,pn,用空格分隔。

输出格式

输出到标准输出。

输出共一行,一个实数,即期望抽卡次数。

样例1输入

2 2
0.4 0.6

Data

样例1输出

2.52

Data

样例1解释

共有 2 种卡牌,不妨记为 A 和 B,获得概率分别为 0.4 和 0.6,2 枚硬币可以换一张卡牌。下面给出各种可能出现的情况:

  • 第一次抽卡获得 A,第二次抽卡获得 B,抽卡结束,概率为 0.4×0.6=0.24,抽卡次数为 2。
  • 第一次抽卡获得 A,第二次抽卡获得 A,第三次抽卡获得 B,抽卡结束,概率为 0.4×0.4×0.6=0.096,抽卡次数为 3。
  • 第一次抽卡获得 A,第二次抽卡获得 A,第三次抽卡获得 A,用硬币兑换 B,抽卡结束,概率为 0.4×0.4×0.4=0.064,抽卡次数为 3。
  • 第一次抽卡获得 B,第二次抽卡获得 A,抽卡结束,概率为 0.6×0.4=0.24,抽卡次数为 2。
  • 第一次抽卡获得 B,第二次抽卡获得 B,第三次抽卡获得 A,抽卡结束,概率为 0.6×0.6×0.4=0.144,抽卡次数为 3。
  • 第一次抽卡获得 B,第二次抽卡获得 B,第三次抽卡获得 B,用硬币兑换 A,抽卡结束,概率为 0.6×0.6×0.6=0.216,抽卡次数为 3。

因此答案是 0.24×2+0.096×3+0.064×3+0.24×2+0.144×3+0.216×3=2.52。

样例2输入

4 3
0.006 0.1 0.2 0.694

Data

样例2输出

7.3229920752

Data

子任务

对于 20% 的数据,保证 1≤n,k≤5。

对于另外 20% 的数据,保证所有 pi 是相等的。

对于 100% 的数据,保证 1≤n≤16,1≤k≤5,所有的 pi 满足 pi≥110000,且 ∑i=1npi=1。

解题思路

看看数据范围,可以用状压dp,用0和1代表选不选

注意保留10位小数,是样例里给出的最长的,保留其他位都是零分,emm,也没给范围,挺怪的

double保留到小数点后15位以后就不准了 

题解

#include<bits/stdc++.h>
using namespace std;
double dp[(1<<17)+17][100];
int cnt[(1<<17)+17];		//判断第i位转化为2进制有几个1 
int main(){
	int n,l;
	cin>>n>>l;
	vector<double> v(n);
	for(int i=0;i<n;i++)	cin>>v[i];
	for(int i=0;i<=(1<<n);i++){
		int x=i;
		while(x>0){
			if(x%2)	cnt[i]++;
			x/=2;
		}
	}
	double ans=0.0;
	dp[0][0]=1;
	for(int i=0;i<(1<<n);i++){
		for(int j=0;j<=100;j++){
			if(cnt[i]+(j-cnt[i])/l==n){		//满足条件 
				ans+=j*dp[i][j];
				continue;
			}
			for(int k=0;k<n;k++){	//不满足条件,遍历插入 
				if(i&(1<<k)){	//已经存在 
					dp[i][j+1]+=dp[i][j]*v[k];
					//cout<<"i: "<<i<<"j: "<<j<<"\n";
				} else{
					dp[i+(1<<k)][j+1]+=dp[i][j]*v[k];
					//cout<<"i+(1<<k): "<<i+(1<<k)<<"i: "<<i<<"j: "<<j<<"\n";
				}
			}
		}
	} 
	printf("%.10f",ans);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值