codeforces 739E - Gosha is hunting
这道题有三种做法,感受一下:
感觉到了歪果仁费尽脑汁想出来的神仙贪心脑洞题被中国人套路算法踩爆的凄凉。。。(我的名字是不是暴露了我的真实实力)
===================================================================================
首先先要明白:有A个A球,B个B球,用了一个A球贡献为ai,B球贡献为bi,两个都用贡献为1-(1-ai)(1-bi)=ai+bi-ai*bi
先讲讲最无脑的费用流吧。。。
显然st先分别流向A球和B球流量为球的个数,费用为0
两种球分别连向所有小精灵,流量为1,费用为贡献
对于小精灵,连向ed分别建一条流量为1费用为0,流量为1费用为-ai*bi的边,这样如果被两种球分别流了,可以减掉多算的
复杂度O(EK)E约等于2n,K是A+B所以大概是O(n^2)带个大常数的,真菜,还是正解有意思
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std; struct node
{
int x,y,c,next;double d;
}a[];int len,last[];
void ins(int x,int y,int c,double d)
{
len++;
a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
a[len].next=last[x];last[x]=len; len++;
a[len].x=y;a[len].y=x;a[len].c=;a[len].d=-d;
a[len].next=last[y];last[y]=len;
} int st,ed;
int pre[],c[]; double d[],ans;
int list[];bool v[];
bool spfa()
{
memset(d,-,sizeof(d));d[st]=;c[st]=(<<);
memset(v,false,sizeof(v));v[st]=true;
int head=,tail=;list[]=st;
while(head!=tail)
{
int x=list[head];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(a[k].c>&&d[y]<d[x]+a[k].d&&(!(d[x]+a[k].d-d[y]<=1e-)))
{
d[y]=d[x]+a[k].d;
c[y]=min(a[k].c,c[x]);
pre[y]=k;
if(v[y]==false)
{
v[y]=true;
list[tail]=y;
tail++;if(tail==)tail=;
}
}
}
v[x]=false;
head++;if(head==)head=;
}
if(fabs(d[ed]-d[])<=1e-)return false;
else
{
int y=ed;ans+=c[ed]*d[ed];
while(y!=st)
{
int k=pre[y];
a[k].c-=c[ed];
a[k^].c+=c[ed];
y=a[k].x;
}
return true;
}
} double A[],B[];
int main()
{
int n,m,aa,bb;
scanf("%d%d%d",&n,&aa,&bb);
for(int i=;i<=n;i++)scanf("%lf",&A[i]);
for(int i=;i<=n;i++)scanf("%lf",&B[i]); len=;st=n+,ed=n+;
ins(st,n+,aa,),ins(st,n+,bb,);
aa=n+,bb=n+;
for(int i=;i<=n;i++)
{
ins(aa,i,,A[i]);
ins(bb,i,,B[i]);
ins(i,ed,,);
ins(i,ed,,-A[i]*B[i]);
} while(spfa());
printf("%.6lf\n",ans); return ;
}
费用流
------------------------------------------------------------------------------
这是瑟瑟发抖的官方钦定贪心。。。
大前提:A球和B球都要完全用完,用得越多期望一定越大
考虑先按B的贡献大到小给小精灵排序,然后枚举最后一个B球用的位置i(这个位置必定不会超过A+B),这样右边的只有可能是不用或用a(然并卵)
这只是构建了一个前提,使得1~i之中必定每个小精灵都用了球,如果中间没有选A球替代B球,B球一定是贪心选择前B个的
我们先假设1~i之中全部都只用了B球,再考虑A球的放法
对于两个球都放而言,对于B球用的个数没有影响,对于贡献的影响为a-a*b
而B球只有B个却放了i个,意味着要用i-B次单独选择A球来替换(注意是刚好i-B次),对于贡献的影响为a-b
考虑对于当前1~i再次排序贪心,如果我们把双选放前面,单A放后面,使得这样的选择方案是最优的,我们用邻项交换的方式做一下:
设二次排序后x<y,x小精灵用两个球,y小精灵用A球,则有ax+bx-ax*bx+ay>ay+by-ay*by+ax 即 bx-ax*bx>by-ay*by
所以我们按照b*(1-a)大到小排序,这样就把两种选择方式分成两段了
然而我们还是不知道断点在哪里,所以我们需要枚举断点j
于是:要在j~i中选择前i-B个贡献最大的(贡献是a-b),以及在1~j-1中(贡献是a-a*b)和i+1~n中(贡献为a)找到A-(i-B)个最大的
这是一个求全局前k大的数的和的问题,可以用数据结构解决
我%的是CQzhangyu(全网唯一写这个的)%到吐于是乎顺便跟着也用了对顶堆其实是复制粘贴splay各种操作拼起来不知道哪里出锅了,你也可以写个平衡树来d飞我啊~~~~
复杂度O(n^2logn)跑得可真快呢像我的常数一样快,真棒!
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const double eps=1e-; struct heap
{
priority_queue<double>a,b;
void del(){while(!b.empty()&&fabs(a.top()-b.top())<=eps)a.pop(),b.pop();}
double top(){del();return a.top();}
void pop(){del();a.pop();}
int size(){return a.size()-b.size();} void push (double x){a.push(x);}
void erase(double x){b.push(x);}
void clear()
{
while(!a.empty())a.pop();
while(!b.empty())b.pop();
}
};
double sum;
struct bst
{
heap A,B; int lim;
void insert(double x)
{
A.push(-x),sum+=x;
if(A.size()>lim)
B.push(-A.top()),sum+=A.top(),A.pop();
}
void del(double x)
{
if(B.size()>&&x<=B.top())B.erase(x);
else
{
sum-=x,A.erase(-x);
if(A.size()<lim&&B.size()>)
A.push(-B.top()),sum+=B.top(),B.pop();
}
}
void clear(){A.clear(),B.clear();}
}H[];
void init(int l1,int l2)
{
H[].clear(),H[].lim=l1;
H[].clear(),H[].lim=l2;
sum=;
} //---------------------------------findkth---------------------------------------------------- struct node{double a,b;}p[];
bool cmp(node n1,node n2){return n1.b>n2.b;}
bool cmd(node n1,node n2){return n1.b*(-n1.a)>n2.b*(-n2.a);}
int main()
{
int n,A,B;
scanf("%d%d%d",&n,&A,&B);
for(int i=;i<=n;i++)scanf("%lf",&p[i].a);
for(int i=;i<=n;i++)scanf("%lf",&p[i].b);
sort(p+,p+n+,cmp); double ss=;for(int i=;i<B;i++)ss+=p[i].b;
double ans=; int li=min(n,A+B);
for(int i=B;i<=li;i++)
{
ss+=p[i].b; sort(p+,p+i+,cmd);
init(i-B,A-(i-B));
for(int j= ;j<=i;j++)H[].insert(p[j].a-p[j].b);
for(int j=i+;j<=n;j++)H[].insert(p[j].a);
ans=max(ans,ss+sum);
for(int j=;H[].lim<=i-j;j++)
{
H[].del(p[j].a-p[j].b);
H[].insert(p[j].a-p[j].a*p[j].b);
ans=max(ans,ss+sum);
}
}
printf("%.6lf\n",ans); return ;
}
真惨
----------------------------------------------------------------------
终于进入到了我做这道题的真正目的:练wqs二分
无脑的dp方程:f[i][j][k]表示枚举到第i个小精灵,用了j个A球k个B球
记得我之前讲了啥:A球和B球都要完全用完,用得越多期望一定越大
前面一句联想到wqs二分套路固定选择k个,后面一句说明它的函数值是单调增的,同时用你聪明(???)的脑子想想就知道它是一个上凸包,因为先选的时候肯定是贪心选最大的(注意到这个要求的是最大值,所以二分的值是要减掉的(以前没见过))
因为有两维,我们可以wqs套wqs
你问DP转移?这还用脑子吗?
复杂度O(nlog^2n)也太无聊了,虽然和正解一样又有log又有^2,可是^2在log后面真丑~
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-; int n,A,B;
double a[],b[];
double f[],g[],h[];
void DP(double x,double y)
{
f[]=;g[]=;h[]=;
for(int i=;i<=n;i++)
{
f[i]=f[i-],g[i]=g[i-],h[i]=h[i-];
double d2=f[i-]+a[i]-x;
double d3=f[i-]+b[i]-y;
double d4=f[i-]+a[i]+b[i]-a[i]*b[i]-x-y;
if(f[i]<d2&&fabs(d2-f[i])>eps) f[i]=d2, g[i]=g[i-]+, h[i]=h[i-];
if(f[i]<d3&&fabs(d3-f[i])>eps) f[i]=d3, g[i]=g[i-] , h[i]=h[i-]+;
if(f[i]<d4&&fabs(d4-f[i])>eps) f[i]=d4, g[i]=g[i-]+, h[i]=h[i-]+;
}
} void wqs(double x)
{
double l=,r=,y;
while(r-l>eps)
{
double mid=(l+r)/;
DP(x,mid);
if(h[n]<=B)
{
y=mid;
r=mid;
}
else l=mid;
}
DP(x,y);f[n]+=B*y;
} int main()
{
scanf("%d%d%d",&n,&A,&B);
for(int i=;i<=n;i++)scanf("%lf",&a[i]);
for(int i=;i<=n;i++)scanf("%lf",&b[i]); double l=,r=,ans;
while(r-l>eps)
{
double mid=(l+r)/;
wqs(mid);
if(g[n]<=A)
{
ans=f[n]+A*mid;
r=mid;
}
else l=mid;
}
printf("%.6lf\n",ans); return ;
}
wqs二分
codeforces 739E - Gosha is hunting的更多相关文章
- Codeforces.739E.Gosha is hunting(DP 带权二分)
题目链接 \(Description\) 有\(n\)只精灵,两种精灵球(高级和低级),每种球能捕捉到第\(i\)只精灵的概率已知.求用\(A\)个低级球和\(B\)个高级球能捕捉到精灵数的最大期望. ...
- Codeforces 749E Gosha is hunting 二分+DP
很神奇的一题 看完题解不由惊叹 题意:$n$个神奇宝贝 $a$个普通球 $b$个高级球 普通球抓住$i$神奇宝贝的概率为$u[i]$ 高级球为$p[i]$ 一起用为$u[i]+p[i]-u[i]*p[ ...
- CF 739E Gosha is Hunting
有 $n$ 个 Pokemon,你有 $A$ 个一类精灵球,$B$ 个二类精灵球 分别给出每个 Pokemon 被这两类精灵球捕捉的概率 求抓到 Pokemon 的最优期望个数 $n\leq 2000 ...
- 【CF739E】Gosha is hunting 贪心
[CF739E]Gosha is hunting 题意:有n个小精灵,你有a个普通球和b个超级球,用普通球抓住第i只小精灵的概率为$A_i$,用超级球抓住第i只小精灵的概率为$u_i$.你必须一开始就 ...
- 【CF739E】Gosha is hunting(动态规划,凸优化)
[CF739E]Gosha is hunting(动态规划,凸优化) 题面 洛谷 CF 题解 一个\(O(n^3)\)的\(dp\)很容易写出来. 我们设\(f[i][a][b]\)表示前\(i\)个 ...
- HZOJ 赤(CF739E Gosha is hunting)
本来没有打算写题解的,时间有点紧.但是这个wqs二分看了好久才明白还是写点东西吧. 题解就直接粘dg的了: 赤(red) 本题来自codeforces 739E,加大了数据范围. 首先对一只猫不会扔两 ...
- Codeforces739E Gosha is hunting
题意:现在有n个精灵,两种精灵球各m1和m2个,每个精灵单独使用第一种精灵球有pi的概率被捕获,单独使用第二种精灵球有ui的概率被捕获,同时使用有1-(1-pi)*(1-ui)的概率被捕获.一种精灵球 ...
- CF739E Gosha is hunting DP+wqs二分
我是从其他博客里看到这题的,上面说做法是wqs二分套wqs二分?但是我好懒呀,只用了一个wqs二分,于是\(O(nlog^2n)\)→\(O(n^2logn)\) 首先我们有一个\(O(n^3)\)的 ...
- 2019.03.12 codeforces739E. Gosha is hunting(dp凸优化)
传送门 题意:nnn个物品,有aaa个XXX道具和bbb个YYY道具,XXX道具移走第iii个物品概率为pip_ipi,YYY道具移走第iii个道具概率为uiu_iui. 对于每个物品每种道具最多 ...
随机推荐
- 算法导论 第一章and第二章(python)
算法导论 第一章 算法 输入--(算法)-->输出 解决的问题 识别DNA(排序,最长公共子序列,) # 确定一部分用法 互联网快速访问索引 电子商务(数值算 ...
- [MVC][Shopping]Copy Will's Code
数据模型规划(Models) //DisplayNameAttribute 指定属性的显示名称 [DisplayName("商品类别")] //DisplayColumnAttri ...
- C#通信学习(一)
基础知识 TCP/IP:Transmission Control Protocol/Internet Protocol,传输控制协议/因特网互联协议,又名网络通讯协议.简单来说:TCP控制传输数据,负 ...
- 什么样的经历,才能领悟成为架构师? >>>
什么样的经历,才能领悟成为架构师? >>> 本文主要分析 SpringBoot 的启动过程. SpringBoot的版本为:2.1.0 release,最新版本. 一.时序图 还是老 ...
- [luoguP2704] 炮兵阵地(状压DP)
传送门 可以事先把每一行的所有状态处理出来,发现每一行的状态数最多不超过60个 f[i][j][k]表示前i行,第i行为状态j,第i-1行为状态k的最优解 #include <vector> ...
- JPA框架下使用纯粹的原生SQL
最近遇到一个需求,查询数据库中对应表的字段是动态的,项目使用的框架使用JPA+Spring Boot,JPA自带原生SQL支持的传入参数是强类型的,无法用于查询语句的字段更改,因为插入字符串的话带有单 ...
- hdu 4043 FXTZ II [ 概率 + Java大数]
传送门 FXTZ II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- C# 通过T4自动生成代码
通过T4模板生成代码,运行时实现 关键代码段:Host using Microsoft.VisualStudio.TextTemplating; using System; using System. ...
- oracle coherence介绍及使用
网上除了官方用户指南,关于Coherence的介绍文章资料很少,因此总结出此文,从原理到快速指南和基本最佳实践,希望对需要的人提供一个参考. 1 Coherence 概述 1.1 Coherence是 ...
- IOS开发 序列化与反序列化
原帖地址:http://blog.csdn.net/ally_ideveloper/article/details/7956942 不会用,记下自己有时间看 序列化与反序列化概述 序列化,它又称串行化 ...