2018.10.13 bzoj4008: [HNOI2015]亞瑟王(概率dp)
阿新 • • 發佈:2018-12-15
傳送門 馬上2點考初賽了,心裡有點小緊張。 做道概率dp壓壓驚吧。 話說這題最開始想錯了。 最開始的方法是考慮表示第輪出牌為的概率。 然後用第輪~都不選的概率與前輪都不選的概率轉移。 但這樣是錯的。 因為兩個轉移的量是有交集的。 因此需要換一種狀態定義方式。 我們考慮表示前張出了張的概率(注意是針對所有輪加起來)。 然後轉移就很了。 程式碼:
#include<bits/stdc++.h>
#define db double
using namespace std;
int n,r,T;
db mul[250][250],f[250][250],d[250],p[250],psum[250],ans;
inline void init(){
for(int i=1;i<=n;++i){
mul[i][0]=1;
for(int j=1;j<=r;++j)mul[i][j]=mul[i][j-1]*(1-p[i]);
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&r),ans=0;
for (int i=1;i<=n;++i)scanf("%lf%lf",&p[i],&d[i]);
memset(f,0,sizeof(f)),memset(psum,0,sizeof(psum)),init();
f[1][0]=mul[1][r],f[1][1]=psum[1]=1-f[1][0];
for(int i=2;i<=n;++i){
for(int j=0;j<=r;++j){
psum[i]+=f[i-1][j]*(1-mul[i][r-j]),f[i][j]+=f[i-1][j]*mul[i][r-j];
if(j)f[i] [j]+=f[i-1][j-1]*(1-mul[i][r-j+1]);
}
}
for(int i=1;i<=n;++i)ans+=psum[i]*d[i];
printf("%.10lf\n",ans);
}
return 0;
}