守卫者的挑战

守卫者的挑战链接可能会挂

\(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(); }

posted @ 2021-05-26 11:12  -OMA-  阅读(126)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end