1. 程式人生 > >Codeforces.739E.Gosha is hunting(DP 帶權二分)

Codeforces.739E.Gosha is hunting(DP 帶權二分)

void lse () algorithm 進行 總結 include line lin

題目鏈接

\(Description\)

有n只精靈,兩種精靈球,每種球能捕捉到第i只精靈的概率已知。求用A個低級球和B個高級球能捕捉到精靈數的最大期望。

\(Solution\)

設f[i][a][b]表示前i只用了a個低級球,b個高級球的最大期望。轉移時四種情況顯然。復雜度\(\mathcal O(nAB)\)
隨著某種球可使用數的增多,f應是凸函數,即增長越來越慢。而且兩種球都滿足這個性質。
於是可以wqs二分套wqs二分了。。沒有個數限制取個max記一下個數就可以了。復雜度\(\mathcal O(nlog^2n)\)
誤差<=1e-4,因為最後要*A/B,所以eps應是1e-8。

必須取r感覺不太懂。。

總結(個人理解):對於有著次數/段數之類的限制,可以使用帶權二分來消掉這一限制,從而可以進行簡單的快速DP。

//46ms    0KB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define eps (1e-12)
const int N=2003;

int n,A,B,na[N],nb[N];
double pa[N],pb[N],Ans;

void Solve(double ca,double cb)
{
    na[0
]=nb[0]=0; double las=0, now; for(int i=1; i<=n; ++i, las=now) { now=las, na[i]=na[i-1], nb[i]=nb[i-1]; if(las+pa[i]-ca>now) now=las+pa[i]-ca, na[i]=na[i-1]+1; if(las+pb[i]-cb>now) now=las+pb[i]-cb, nb[i]=nb[i-1]+1, na[i]=na[i-1]; if(las+pa[i]+pb[i]-pa[i]*pb[i]-ca-cb>now)//1-(1-pa)(1-pb)
now=las+pa[i]+pb[i]-pa[i]*pb[i]-ca-cb, na[i]=na[i-1]+1, nb[i]=nb[i-1]+1; } Ans=now; } int main() { scanf("%d%d%d",&n,&A,&B); for(int i=1; i<=n; ++i) scanf("%lf",&pa[i]); for(int i=1; i<=n; ++i) scanf("%lf",&pb[i]); double l1=0,r1=1,mid1,l2,r2,mid2;//每個球0/1的權值就可以了啊 while(r1>=l1+eps) { mid1=(l1+r1)*0.5; l2=0, r2=1; while(r2>=l2+eps) { if(Solve(mid1,mid2=(l2+r2)*0.5),nb[n]>B) l2=mid2; else r2=mid2; } if(Solve(mid1,r2),na[n]>A) l1=mid1;//最優可行的是r2?反正不是l2。。 else r1=mid1; } Solve(r1,r2);//最後Check一遍r。。 printf("%.5lf",Ans+A*r1+B*r2); return 0; }

Codeforces.739E.Gosha is hunting(DP 帶權二分)