zl程序教程

您现在的位置是:首页 >  其它

当前栏目

CF167B Wizards and Huge Prize

and
2023-09-11 14:20:14 时间

CF167B Wizards and Huge Prize

洛谷传送门

题意翻译

题目大意:最开始你有k的容积,有n轮比赛,比赛分为两种(具体种类由输入给出),一种的奖品是增加ai容积,另一种增加一个物品,只有到最后的容积装得下所有赢得的物品才算合法的方案,问赢得的比赛总场数>=l的合法方案的概率。 翻译贡献者UID:40199


题解:

期望DP好题。

题目大意他概括的不清晰,我重新说一下:

最开始你有k的容积,有n轮比赛,每轮比赛的胜率为pi,比赛分为两种(具体种类由输入给出,给出ai>=1是第一种,给出-1为第二种),第一种的奖品是增加ai容积,另一种增加一个物品,体积为1,只有到最后的容积装得下所有赢得的物品才算合法的方案,问赢得的比赛总场数>=l的合法方案的概率。

那么设置状态为:\(dp[i][j][k]\)表示当前\(i\)轮游戏,赢了\(j\)次,背包容积为\(k\)时的合法概率。

那么答案就是

\[\sum_{i=l}^{n}\sum_{j=0}^{n}dp[n][i][j] \]

转移的时候也比较好想:背包容积加上这个值之后,如果不超过限制,那么输赢无所谓,否则,就必须要输,否则就和合法的状态相悖。

那么代码:

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxh=210;
const int maxn=3e4+4;
struct node
{
	double p;
	int val;
}a[maxn];
int n,L,k;
double dp[maxh][maxh][maxh];//i轮游戏,赢了j次,背包容积为k 
bool cmp(node a,node b)
{
	return a.val>b.val;
}
int main()
{
	scanf("%d%d%d",&n,&L,&k);
	for(int i=1;i<=n;i++)
    {
	    scanf("%lf",&a[i].p);
        a[i].p/=1.0*100;
    }
	for(int i=1;i<=n;i++)
	    scanf("%d",&a[i].val);
	dp[0][0][min(k,n)]=1;
	sort(a+1,a+n+1,cmp);
	for(int i=0;i<n;i++)
	    for(int j=0;j<=i;j++)
	        for(int l=0;l<=n;l++)
	        {
		        if(l+a[i+1].val>=0)
		            dp[i+1][j+1][l+a[i+1].val>n?n:l+a[i+1].val]+=dp[i][j][l]*a[i+1].p;
		        dp[i+1][j][l]+=dp[i][j][l]*(1-a[i+1].p);
	        }
	double ans=0;
	for(int i=L;i<=n;i++)
	    for(int j=0;j<=n;j++)
	        ans+=dp[n][i][j];
	printf("%.8lf",ans);
	return 0;
}