Codeforces.739E.Gosha is hunting(DP 带权二分)

题目链接

\(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;
}

原文地址:https://www.cnblogs.com/SovietPower/p/9163792.html

时间: 2024-10-08 14:54:12

Codeforces.739E.Gosha is hunting(DP 带权二分)的相关文章

P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分

$ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做"LCT" 的挑战,它的规则是这样子的:现在有一个N 个点的 树(Tree),每条边有一个整数边权vi ,若vi >= 0,表示走这条边会获得vi 的收益:若vi < 0 ,则表示走这条边需要支付- vi 的过路费.小L 需要控制主角Link 切掉(

带权二分

带权二分 一种二分答案的套路,又叫做DP凸优化,wqs二分. 用来解决一类题目,要求某个要求出现K次,并且,可以很显然的发现,在改变相应权值的时候,对应出现的次数具有单调性.而且很显然,这种题一般满足一定的要求.而且一般权值为整数二分就可以,但是有的题需要实数二分...而且,边界条件通常很麻烦,调起来想摔电脑. 例题时间: BZOJ2654: tree 题目大意:给你一个图,里面有白色边和黑色边,问恰好有k条边白色边的最小生成树 直接贪心法肯定是错误的,因此,我们考虑带权二分. 给定一个选择白色

HDU 4359 Easy Tree DP? 带权二叉树的构造方法 dp

题意: 给定n deep 1.构造一个n个节点的带权树,且最大深度为deep,每个节点最多只能有2个儿子 2.每个节点的值为2^0, 2^1 ··· 2^(n-1)  任意两个节点值不能相同 3.对于一个节点,若他有左右儿子,则左子树的和 < 右子树的和 问: 有多少种构造方法. 思路: dp #include <stdio.h> #include <iostream> #include <algorithm> #include <cstring> u

POJ1417:True Liars(DP+带权并查集)

True Liars Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16338    Accepted Submission(s): 5724 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3038 Description: After having drifted about in a

CodeForces - 687D: Dividing Kingdom II (二分图&amp;带权并查集)

Long time ago, there was a great kingdom and it was being ruled by The Great Arya and Pari The Great. These two had some problems about the numbers they like, so they decided to divide the great kingdom between themselves. The great kingdom consisted

CF739E Gosha is hunting DP+wqs二分

我是从其他博客里看到这题的,上面说做法是wqs二分套wqs二分?但是我好懒呀,只用了一个wqs二分,于是\(O(nlog^2n)\)→\(O(n^2logn)\) 首先我们有一个\(O(n^3)\)的暴力\(DP\),转移好写,形式优美,但复杂度不对 该怎样发现它的凸性质呢 1.打表√ 2.冷静分析一波,每一种球肯定是越多越好,于是我们先固定选择\(a\)个普通球,然后那\(b\)个大师球肯定是从大到小挑选.这样的话每多选一个,新增的收益就会下降一点,也就是说这是个上凸函数.(口胡如果假的话,就

codeforces 687D Dividing Kingdom II 带权并查集(dsu)

题意:给你m条边,每条边有一个权值,每次询问只保留编号l到r的边,让你把这个图分成两部分 一个方案的耗费是当前符合条件的边的最大权值(符合条件的边指两段点都在一个部分),问你如何分,可以让耗费最小 分析:把当前l到r的边进行排序,从大到小,从大的开始不断加边,判断当前能否形成二分图,如果能形成二分图,继续加边 如果不能形成二分图,那当前边的权值就是最小耗费(是不是很眼熟) 思路很清晰,现在我们要解决的是如何判断可以形成二分图,有两种,一个是2染色当前图(肯定超时) 所以只剩一种方法,带权并查集

cf739E Gosha is hunting (flows)

739E 有$a$个普通球,$b$个超级球,有$n$个要捕捉的宝可梦,对于第$i$个宝可梦普通球的捕捉概率是$p_i$,超级球的捕捉概率是$u_i$,每种球只能扔一个到同一个宝可梦,同一个宝可梦可以被扔两种球.然后问在最优策略下捕捉个数的期望 考虑概率$dp$,发现状态无法简化到$n^2$级别,原来不是dp 假定每个宝可梦只能被扔一个球,那就是个匹配问题了,设$A$为普通球,$B$为超级球,源点向$A$,$B$连容量为球的个数,花费为$0$的边,$A,B$分别向每个精灵连容量为$1$,花费为$p

poj1417 带权并查集+0/1背包

题意:有一个岛上住着一些神和魔,并且已知神和魔的数量,现在已知神总是说真话,魔总是说假话,有 n 个询问,问某个神或魔(身份未知),问题是问某个是神还是魔,根据他们的回答,问是否能够确定哪些是神哪些是魔. 对于这些问题,我们只需要发现,如果回答对方是魔,那么即可以判断出这两个不是同一种族,而如果回答对方是神,那么说明这两个是同一种族,那么就可以用带权并查集合并这些神和魔,然后记录两种分别多少个,这样当所有询问都处理完时我们就可以得到一系列的集合,每个集合分别有它的两个种族的人数,但是此时对于每个