题意:
给出N道题,和一个概率P,然后给出每道题对应的得分x(每道题只有两个选项,一个正确一个错误)。两个人来答题,一个人是随机选择答案,问另一个人至少要答多少分才能保证有P的概率不会失败。
思路:
01背包,最大分数为40000,01背包处理,记录这40000个分数出现的次数然后从小分数遍历一边即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 40005;
ll dp[maxn], v[45];
int main()
{
ll t, n;
double p;
scanf("%d", &t);
while(t--)
{
scanf("%I64d%lf", &n, &p);
memset(dp, 0, sizeof(dp));
ll sum = 0;
for(int i = 1; i <= n; i++)
{
scanf("%I64d", &v[i]);
sum += v[i];
}
dp[0] = 1;
for(int i = 1; i <= n; i++)
for(int j = sum; j >= v[i]; j--)
dp[j] += dp[j-v[i]];
ll tmp = 1LL << n;
sum = 0;
for(int i = 0; i <= 40000; i++)
{
sum += dp[i];
if(sum*1.0/tmp >= p)
{
printf("%d\n", i);
break;
}
}
}
return 0;
}
概率DP写法:
d[i][j],表示前i道题,得分为j的概率 。 这样,最终打完所有题目之后猴子得任意分数的概率我们就知道了,老虎要想赢就要至少
得和他一样的分数,那么就很好办了,从0~max分,不断相加概率,当概率大于P时的分数就是答案
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 50;
const double INF = 10000000.0;
int T,n,a[maxn];
double p,d[50][40000+100];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%lf",&n,&p);
ll sum = 0;
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum += a[i];
}
memset(d,0,sizeof(d));
d[0][0] = 1.0;
for(int i=1; i<=n; i++)
{
for(int j=0; j<=sum; j++)
{
if(j >= a[i]) d[i][j] += d[i-1][j-a[i]]/2;
d[i][j] += d[i-1][j]/2;
}
}
int ans;
double pp = 0.0;
for(int i=0; i<=sum; i++)
{
pp += d[n][i];
if(pp > p || fabs(pp-p) < 1e-6)
{
ans = i ;
break;
}
}
printf("%d\n",ans);
}
return 0;
}