守卫者的挑战
守卫者的挑战链接可能会挂
设\(dp[i][j][k]\)表示打了\(i\)场,赢了\(j\)场,背包容量为\(k\)时的概率,则有
当第\(i\)场输了的时候
\[dp[i][j][k+n]\;+=dp[i-1][j][k+n]\times \left(1-p[i]\right)
\]
当第\(i\)场赢了的时候
\[dp[i][j+1][\min(k+a[i],n)+n]\;+=dp[i-1][j][k+n]\times p[i]
\]
其中
\(dp[0][0][\min(k,n)+n]=1\),这个里的\(k\)为一开始输入的那个
最后答案则为
\[ans=\sum_{i=l}^n\;\sum_{j=0}^{n}dp[n][i][j+n]
\]
式子中背包容量都加\(n\),是因为它有可能是负的可以选择不放入背包,数组没有负的下标,为了避免这种状况,将整个第三维都右移\(n\)
Code:
#include<cstdio>
#define MAX 201
#define re register
namespace OMA
{
int n,l;
int a[MAX];
double ans;
double p[MAX];
double dp[MAX][MAX][MAX<<1];
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
inline int min(int a,int b)
{ return a<b?a:b; }
void in()
{
n=read(),l=read();
dp[0][0][min(read(),n)+n] = 1;
for(re int i=1; i<=n; i++)
{ p[i] = (double)read()/100; }
for(re int i=1; i<=n; i++)
{ a[i] = read(); }
}
signed main()
{
in();
for(re int i=1; i<=n; i++)
{
for(re int j=0; j<=i; j++)
{
for(re int k=-i; k<=n; k++)
{
dp[i][j][k+n] += dp[i-1][j][k+n]*(1-p[i]);
dp[i][j+1][min(k+a[i],n)+n] += dp[i-1][j][k+n]*p[i];
}
}
}
for(re int i=l; i<=n; i++)
{
for(re int j=0; j<=n; j++)
{ ans += dp[n][i][j+n]; ; }
}
//for(re int i=1; i<=n; i++)
//{ printf("%lf ",p[i]); }
printf("%.6lf\n",ans);
return 0;
}
}
signed main()
{ return OMA::main(); }