其他分享
首页 > 其他分享> > LightOJ - 1274 Beating the Dataset(概率期望)

LightOJ - 1274 Beating the Dataset(概率期望)

作者:互联网

题目链接:Beating the Dataset - LightOJ 1274 - Virtual Judge (ppsucxtt.cn)

简化版题意:某人在蒙题,题目答案只有yes和no两种答案,总共有n道题,一开始你知道了n道题中答案为yes的题目数,你每蒙一道题之后,系统会告诉你正确答案是什么。你遵循的蒙题策略如下:

(1)第一道题目你一定蒙yes

(2)从第二道题目起,你每次蒙的答案都是上一道题的答案,比如说我现在做到了第i题,第i-1题的结果是no,那我第i题就直接蒙no

求你蒙错题的数量的期望值。

题目分析:这道题目我做了很长时间,每次读一遍题就得到一些新的信息(+_+),首先需要知道的一个信息就是答案是随机分布的,下一次的答案取决于当前所剩的yes和no的数量,其次需要挖掘的隐含条件就是比如总共有cntyes个题目是yes,你在第i道题目时恰好碰到了最后一个yes,按照正常人的思维就应该知道之后题目的答案都是no,但是由于第i道题目的答案是yes,所以你第i+1道题目还是会蒙yes,服了~

我们可以用动态规划来解决这道题目,设f[i][j][k]表示你当前做到了第i道题目,第i道及之前的题目中有j道题目正确答案是yes,第i道题目的正确答案是yes/no(k=1/0),利用这个含义我们就可以进行递推了,递推分析如下:

设n道题目中答案为yes的题目一共有cntyes道

j+1<=cntyes时:(意味着之后的答案还可能是yes)

f[i][j][0]代表着第i次答案为no,则我下一次会蒙no,下次答案为yes的概率为(cntyes-j)/(n-i),也就是说这是我下一次蒙错的概率,我下一次蒙对的概率就是1-蒙错概率

f[i][j][1]代表着第i次答案为yes,则我下一次会蒙yes,下次答案为yes的概率为(cntyes-j)/(n-i),也就是说这是我下一次蒙对的概率,我下一次蒙错的概率就是1-蒙对概率

j==cntyes时:(意味着之后的答案全是no)

f[i][j][0]代表着第i次答案是no,因为之后的答案全是no,则我下次一定蒙对,则有f[i][j][0]=f[i+1][j][0]

f[i][j][1]代表着第i次答案是yes,因为之后的答案全是no,则我下次一定蒙错,则有f[i][j][1]=f[i+1][j][0]+1

第一次答案是yes的可能性是cntyes/n,这也就是我第一次蒙对的概率,则我蒙错的概率就是1-cntyes/n,则答案就是f[1][1][1]*cntyes/n+(f[1][0][0]+1)*cntno/n

最后需要注意的时,由于空间原因,所以要开滚动数组

下面是代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=5e3+10;
double f[2][N][2];//表示该状态后面错误次数的期望值  
//f[i][j][k]第一维表示当前处理到第i个回答
//第二维表示第i个位置及之前的题目答案中已经出现了j个YES
//第三维表示第i位答案是YES/NO(1/0)的情况下
int main()
{
	int T,n,m;
	cin>>T;
	for(int o=1;o<=T;o++)
	{
		scanf("%d%d",&n,&m);
		int cntyes=m-2*n;
		int cntno=n-cntyes;
		f[n&1][cntyes][0]=f[n&1][cntyes][1]=0;//终止态 
		for(int i=n-1;i>=1;i--)
		{
			int minyes=max(0,i-cntno);
			int maxyes=min(i,cntyes);
			for(int j=minyes;j<=maxyes;j++)
			{
				double pyes=1.0*(cntyes-j)/(n-i);//下一次答案为yes的概率 
				double pno=1-pyes;//下一次答案为no的概率 
				if(j+1<=cntyes)//第i次之后的答案还可能出现yes 
				{
					f[i&1][j][0]=pyes*(f[(i+1)&1][j+1][1]+1)+pno*f[(i+1)&1][j][0];//第i个位置答案是no,则下一次猜no,有pyes的概率猜错 
					f[i&1][j][1]=pyes*f[(i+1)&1][j+1][1]+pno*(f[(i+1)&1][j][0]+1);//第i个位置答案是yes,则下一次猜yes,有(1-pyes)的概率猜错 
				}
				else//第i次之后的答案只能是no 
				{
					f[i&1][j][0]=f[(i+1)&1][j][0];//第i个位置答案是no,则下一次猜no,一定猜对 
					f[i&1][j][1]=f[(i+1)&1][j][0]+1;//第i个位置答案是yes,则下一次猜yes,一定猜错,期望+1 
				}
			}
		}
		double ans=f[1][1][1]*cntyes/n+(f[1][0][0]+1)*cntno/n;//第一次答案为yes的概率为cntyes/n,也就是说第一次猜对的概率为cntyes/n
		printf("Case %d: %.10lf\n",o,ans);
	}
	return 0;
}

标签:题目,no,int,LightOJ,1274,Dataset,cntyes,答案,yes
来源: https://blog.csdn.net/AC__dream/article/details/121001142