• 【CF739E】Gosha is Hunting-期望DP+WQS二分


    测试地址:Gosha is Hunting
    题目大意:n只精灵,有a个精灵球和b个大师球,用精灵球抓住精灵i的概率为pi,用大师球抓住精灵i的概率为qi,不能用两个或以上相同种类的球重复捕捉同一只精灵,问能捕捉到的精灵的最大期望数目。
    做法:本题需要用到期望DP+WQS二分。
    首先很快能想到一个DP:令f(i,a,b)为前i只精灵,用了a个精灵球,b个大师球的最大期望,我们只用考虑对于当前精灵,不用任何球,用精灵球,用大师球,精灵球和大师球都用四种情况转移即可。
    然而这样是O(n3)的,显然无法通过。注意到题目中的限制有可能可以使用WQS二分,于是我们一看,f(i,a,b)在固定i,a是,关于b的函数是上凸的,因为显然用的球越多,产生的收益就越小。所以内层直接使用WQS二分,时间复杂度O(n2logC)
    这样已经差不多可以通过此题了,但还有更好的做法。和上面同理,因为f(i,a,b)在固定i,b时,关于a的函数是上凸的,所以a这一维也可以使用WQS二分,这样时间复杂度就是O(nlog2C)的了,可以飞快地通过此题。
    还有一点要注意,是这种涉及实数二分的题的常见问题,因为最优方案会突变,所以在最后选择左右端点上的方案时,选取使得最优的a,b更小的那个端点就能避免这个问题。
    以下是本人代码:

    #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;
    }
  • 相关阅读:
    HTTP协议【详解】——经典面试题
    原生JS的地区二级联动,很好理解的逻辑
    js操作字符串的常用方法
    移除input框type="number"在部分浏览器的默认上下按钮
    atom
    解决gitHub下载速度慢的问题
    ATOM常用插件推荐
    脚踝扭伤肿了怎么办
    这才是真正的电子科大
    月入 7000,怎么存钱?
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793302.html
Copyright © 2020-2023  润新知