题目链接:https://codeforces.com/problemset/problem/167/B
题目大意:有n场比赛,你至少要赢l次才算优秀,你有一个大小为k的包,每场比赛的胜率为$p_i$,每场比赛赢得的奖品为$a_i$如果$a_i<0$则是奖品,否则就是一个容量为$a[i]$的背包。问你在优秀的时候拿走所以赢得奖品的概率。
Examples
Input
3 1 0
10 20 30
-1 -1 2
Output
0.300000000000
Input
1 1 1
100
123
Output
1.000000000000
DP。。。真的有点无力。。。。
设置状态为$dp[i][j][k]$,表示为前$i$场比赛赢得$j$场后的背包剩余空间$k$。由于比赛的顺序是无序的,那么我们可以对初始状态背包容量+200(因为最多200个奖品),那么这样就可以随便拿了,最后确定状态的时候小于200的就直接舍弃了。
以下是AC代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int mac=210; int a[mac]; double p[mac]; double dp[mac][mac][2*mac]; int main() { int n,l,v; scanf ("%d%d%d",&n,&l,&v); for (int i=1; i<=n; i++) scanf ("%lf",&p[i]),p[i]/=100; for (int i=1; i<=n; i++) scanf ("%d",&a[i]); dp[0][0][v+200]=1; for (int i=0; i<n; i++) for (int j=0; j<=i; j++) for (int k=0; k<=400; k++){//枚举空间 int last=min(k+a[i+1],400); dp[i+1][j][k]+=dp[i][j][k]*(1-p[i+1]);//本场失败 if (last>0) dp[i+1][j+1][last]+=dp[i][j][k]*p[i+1]; } double ans=0; for (int i=200; i<=400; i++) for (int j=l; j<=n; j++) ans+=dp[n][j][i]; printf("%.10f ",ans); return 0; }