守卫者的挑战

https://www.zybuluo.com/ysner/note/1239414

题面

初始值为\(k\),现经过一段数,有\(p_i\)的概率加上第\(i\)个数\(a_i\)。问最后值\(\geq0\)且加了\(l\)个数的概率。

  • \(0\leq k\leq2000,0\leq n\leq200,-1\leq a_i\leq1000\)

    解析

    注意到\(k>200\)都是没有意义的,于是可以把\(k\)的范围视为\(0\leq k\leq200\)
    直接设\(f[i][j][k]\)表示处理了第\(1-i\)个数,加了\(j\)个数,值为\(k\)的概率。
    决策就是是否加上这个数。

为了防止第三维变负,\(k+=200\),空间要开到\(400\)
注意到因为\(double\)\(8\)字节,\(128MB\)下该数组会导致\(MLE\)
滚掉第一维即可。

复杂度\(O(n^3)\)\(n,k\)同阶)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int mod=1e9+7,N=1e6+100;
int n,l,k,sum;
long double dp[2][205][410],ans;
struct cha{int w;long double p;}a[N];
il ll gi()
{
   re ll x=0,t=1;
   re char ch=getchar();
   while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
   if(ch=='-') t=-1,ch=getchar();
   while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
   return x*t;
}
il int del(re int x)
{
  if(x>400) return 400;
}
int main()
{
  freopen("guard.in","r",stdin);
  freopen("guard.out","w",stdout);
  n=gi();l=gi();k=gi();k=min(k+200,400);
  fp(i,1,n) scanf("%Lf",&a[i].p);fp(i,1,n) a[i].w=gi();
  re int now=1,nxt=0;
  fp(i,200,400) fp(j,l,n) dp[now][j][i]=1;
  fq(i,n,1)
  {
    swap(now,nxt);
    memset(dp[now],0,sizeof(dp[now]));
    fp(j,0,i)
      fp(v,0,400)
      {
    dp[now][j][v]+=a[i].p*dp[nxt][j+1][del(v+a[i].w)]/100;
    dp[now][j][v]+=(100-a[i].p)*dp[nxt][j][v]/100;
      }
  }
  printf("%.6Lf\n",dp[now][0][k]);
  fclose(stdin);
  fclose(stdout);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/yanshannan/p/9427026.html
今日推荐