背包计数真神奇。
概率dp也神奇。
https://cn.vjudge.net/contest/157865#problem/C
简明说一下题意,有一个机器变态人,大概和汉芯一样,是个骗人的玩意,
出了n个问题,变态人其实只能随机的选择答案,得到的分数是未知的。
给定一个概率,小老虎想确保这个赢他的概率。
问你最少需要答对多少题。
那么重点便在于对题意的理解了。
只要x/y>=p,x为小老虎大于机器人的频数,y代表小老虎的所有频数。
y为2的n次方,x自己累加就行。
卡的地方:1<<42错了,,太大了,改成pow就对了,。
或者用1ll<<42,在位移之前就将其改变成long long了
(普通的转化也不行哦。)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
/* 这个概率dp的做法
*/
double dp[50][44001];
int a[50],b[50];
int main()
{
int x,y,t;
double h;
cin>>t;
while(t--)
{
cin>>x>>h;
int sum=0;
for(int i=1;i<=x;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
b[i]=sum;
}
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=1;i<=x;i++)
for(int j=0;j<=sum;j++)
{ if(a[i]<=j)
dp[i][j]=(dp[i-1][j]+dp[i-1][j-a[i]])*0.5;//上一次是这个份的1/2加上 上一次比这个份低了的1/2;
else
dp[i][j]=dp[i-1][j]*0.5;//上一次是这个分的二分之1,(剩下1/2也可能是被人家抢走了);
}
double g=0;
}
for(int i=0;i<=sum;i++)
{
g+=dp[x][i];
if(g>=h)
{
printf("%d\n",i);
break;
}
}
}
return 0;
}
01背包
#include <bits/stdc++.h>
const int maxn=440005;
using namespace std;
int main()
{ int t;
int m;
double p;
int a[60];
int dp[maxn];
int sum=0;
scanf("%d",&t);
while(t--)
{ sum=0;
scanf("%d%lf",&m,&p);
for(int i=0;i<m;i++)
{ scanf("%d",&a[i]);
sum+=a[i];
}
memset(dp,0,sizeof(dp));
dp[0]=1;
for(int i=0;i<m;i++)
for(int j=sum;j>=a[i];j--)
dp[j]+=dp[j-a[i]];
//long long tim=ceil(pow(2,m)*p);
long long tim=ceil((1ll<<m)*p);
//cout<<tim<<endl;
//for(int i=0;i<sum;i++)
// printf("%d ",dp[i]);
long long num=0;
for(int i=0;i<=sum;i++)
{ num+=dp[i];
if(num>=tim)
{ printf("%d\n",i);
break;
}
}
// printf("e");
}
return 0;
}