测试地址:Gosha is Hunting
题目大意:有只精灵,有个精灵球和个大师球,用精灵球抓住精灵的概率为,用大师球抓住精灵的概率为,不能用两个或以上相同种类的球重复捕捉同一只精灵,问能捕捉到的精灵的最大期望数目。
做法:本题需要用到期望DP+WQS二分。
首先很快能想到一个DP:令为前只精灵,用了个精灵球,个大师球的最大期望,我们只用考虑对于当前精灵,不用任何球,用精灵球,用大师球,精灵球和大师球都用四种情况转移即可。
然而这样是的,显然无法通过。注意到题目中的限制有可能可以使用WQS二分,于是我们一看,在固定是,关于的函数是上凸的,因为显然用的球越多,产生的收益就越小。所以内层直接使用WQS二分,时间复杂度。
这样已经差不多可以通过此题了,但还有更好的做法。和上面同理,因为在固定时,关于的函数是上凸的,所以这一维也可以使用WQS二分,这样时间复杂度就是的了,可以飞快地通过此题。
还有一点要注意,是这种涉及实数二分的题的常见问题,因为最优方案会突变,所以在最后选择左右端点上的方案时,选取使得最优的更小的那个端点就能避免这个问题。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
const double eps=1e-8;
int n,a,b,numa[2010],numb[2010];
double p[2010],q[2010],f[2010];
int solve(double x,double y)
{
f[0]=0.0,numa[0]=0,numb[0]=0;
for(int i=1;i<=n;i++)
{
f[i]=f[i-1];
numa[i]=numa[i-1];
numb[i]=numb[i-1];
if (f[i-1]+p[i]-x>f[i])
{
f[i]=f[i-1]+p[i]-x;
numa[i]=numa[i-1]+1;
numb[i]=numb[i-1];
}
if (f[i-1]+q[i]-y>f[i])
{
f[i]=f[i-1]+q[i]-y;
numa[i]=numa[i-1];
numb[i]=numb[i-1]+1;
}
if (f[i-1]+p[i]+q[i]-p[i]*q[i]-x-y>f[i])
{
f[i]=f[i-1]+p[i]+q[i]-p[i]*q[i]-x-y;
numa[i]=numa[i-1]+1;
numb[i]=numb[i-1]+1;
}
}
}
int main()
{
scanf("%d%d%d",&n,&a,&b);
for(int i=1;i<=n;i++)
scanf("%lf",&p[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&q[i]);
double l1=0.0,r1=1.0,l2,r2;
while(r1-l1>eps)
{
double mid1=(l1+r1)/2.0;
l2=0.0,r2=1.0;
while(r2-l2>eps)
{
double mid2=(l2+r2)/2.0;
solve(mid1,mid2);
if (numb[n]>b) l2=mid2;
else r2=mid2;
}
solve(mid1,r2);
if (numa[n]>a) l1=mid1;
else r1=mid1;
}
solve(r1,r2);
printf("%.8lf",f[n]+r1*(double)a+r2*(double)b);
return 0;
}