如果没有秒杀,就是经典的国王游戏问题,按t/a从小到大排序即可。

考虑删除两个数i<j能给答案减少的贡献:S[i]*T[i]+P[i-1]*A[i]-A[i]+S[j]*T[j]+P[j-1]*A[j]-A[j]-T[i]*A[j]

其中P为T=(D-1)/ATK+1的前缀和,S为A的后缀和。

我们设bi=S[i]*T[i]+P[i-1]*A[i]-A[i],考虑当i固定时,j可能取什么值。

解法一:CDQ分治

不难发现,当i<j<k时k比j优的充要条件是b[k]-T[i]*A[k]>b[j]-T[i]*A[j],即T[i]<(b[k]-b[j])/(A[k]-A[j])。

不难看出斜率优化的模型,最后要最大化的是b[k]-T[i]*A[k]即所有点(A[k],b[k])以-T[i]的斜率投影到y轴上的最高点,于是答案一定在上凸壳上。

注意到这里点的横坐标A和询问斜率T均不单调,需要CDQ分治。

每次分治左半边按T排序,右半边按A排序并将凸包建好,然后左端点从前往后扫即可。

 #include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,m,q[N];
ll A,B,ans,tot,c[N];
struct P{ int x,y; ll z; }a[N],b[N]; bool cmp(const P &a,const P &b){ return a.x*b.y>b.x*a.y; }
bool cmp2(const P &a,const P &b){ return a.y>b.y; }
bool cmp3(const P &a,const P &b){ return a.x<b.x; }
ll calc(int x,int y){ return tot-a[x].z-a[y].z+a[y].x*a[x].y; }
double sl(int x,int y){ return (double)(a[y].z-a[x].z)/(a[y].x-a[x].x); } void solve(int l,int r){
if (l>=r) return;
int mid=(l+r)>>;
solve(l,mid); solve(mid+,r);
sort(a+l,a+mid+,cmp2); sort(a+mid+,a+r+,cmp3);
int st=,ed=;
rep(i,mid+,r){
while (st<ed && sl(q[ed-],q[ed])<sl(q[ed],i)) ed--;
q[++ed]=i;
}
rep(i,l,mid){
while (st<ed && sl(q[st],q[st+])>a[i].y) st++;
ans=min(ans,calc(i,q[st]));
}
} int main(){
freopen("bzoj4700.in","r",stdin);
freopen("bzoj4700.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,n) scanf("%d%d",&a[i].x,&a[i].y),A+=a[i].x,a[i].y=(a[i].y-)/m+;
sort(a+,a+n+,cmp);
rep(i,,n){
A-=a[i].x; B+=a[i].y;
a[i].z=a[i].x*(B-)+A*(a[i].y);
tot+=a[i].x*(B-);
}
ans=tot; solve(,n); printf("%lld\n",ans);
return ;
}

解法二:李超树

不难发现,i固定时,j对答案减小的贡献是b[j]-T[i]*A[j],这个式子可以理解为直线y=-A[j]*x+b[j]在T[i]处的总坐标。

问题转化为,i从大到小枚举,需要支持插入一条直线与在线查询某个横坐标上所有直线总坐标最大值。

动态维护凸包问题,显然用李超树。

 #include<cstdio>
#include<algorithm>
#define ls (x<<1)
#define rs (ls|1)
#define lson ls,L,mid
#define rson rs,mid+1,R
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int n,m,v[N<<];
ll tot,ans,res,L[N],S[N],k[N],b[N];
struct P{ int a,t; }p[N];
bool operator <(const P &a,const P &b){ return a.a*b.t>b.a*a.t; }
bool pd(int x,int y,int p){ return k[x]*p+b[x]>k[y]*p+b[y]; }
ll calc(int x,int p){ return k[x]*p+b[x]; } void ins(int x,int L,int R,int p){
if (L==R){ if (pd(p,v[x],L)) v[x]=p; return; }
int mid=(L+R)>>;
if (k[p]>k[v[x]]){
if (pd(p,v[x],mid)) ins(lson,v[x]),v[x]=p; else ins(rson,p);
}else{
if (pd(p,v[x],mid)) ins(rson,v[x]),v[x]=p; else ins(lson,p);
}
} void que(int x,int L,int R,int k){
res=max(res,calc(v[x],k));
if (L==R) return;
int mid=(L+R)>>;
if (k<=mid) que(lson,k); else que(rson,k);
} int main(){
freopen("bzoj4700.in","r",stdin);
freopen("bzoj4700.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,n) scanf("%d%d",&p[i].a,&p[i].t),p[i].t=(p[i].t-)/m+;
sort(p+,p+n+);
rep(i,,n) L[i]=L[i-]+p[i].t;
for (int i=n; i; i--) S[i]=S[i+]+p[i].a;
rep(i,,n) k[i]=-p[i].a,b[i]=S[i]*p[i].t+L[i-]*p[i].a-p[i].a,tot+=p[i].t*S[i]-p[i].a;
ins(,,n,n);
for (int i=n-; i; i--)
res=,que(,,n,p[i].t),ans=max(ans,b[i]+res),ins(,,n,i);
printf("%lld\n",tot-ans);
return ;
}

[BZOJ4700]适者(CDQ分治+DP/李超线段树)的更多相关文章

  1. Codechef TSUM2 Sum on Tree 点分治、李超线段树

    传送门 点分治模板题都不会迟早要完 发现这道题需要统计所有路径的信息,考虑点分治统计路径信息. 点分治之后,因为路径是有向的,所以对于每一条路径都有向上和向下的两种.那么如果一条向上的路径,点数为\( ...

  2. cdqz2017-test10-rehearsal(CDQ分治&可持久化线段树&单调栈)

    题意: 给出n个三元组 e[i]=(si,ti,wi) 第i个三元组的价值为 Σ w[j] ,j 满足以下4个条件: 1.j<i 2.tj<ti 3.sj<si 4.不存在j< ...

  3. Codeforces 1175G Yet Another Partiton Problem [DP,李超线段树]

    Codeforces 思路 首先吐槽一句:partiton是个什么东西?我好像在百度翻译里面搜不到呀qwq 发现不了什么性质,那就直接上DP吧.注意到DP可以分层,所以设\(dp_i\)表示当前层,分 ...

  4. [CF1303G] Sum of Prefix Sums - 点分治,李超线段树

    给定一棵 \(n\) 个点的带点权的树,求树上的路径 \(x_1,...,x_k\) ,最大化 \(\sum_{i=1}^k ia_{x_i}\) Solution 树上路径问题可用点分治. 考虑如何 ...

  5. Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)

    Codeforces 题面传送门 & 洛谷题面传送门 个人感觉这题称不上毒瘤. 首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不 ...

  6. luogu4849 寻找宝藏 (cdq分治+dp)

    设f[i]是已经走到i号点的值. 先要给第四维离散化.然后去重 第一维排序,第二维cdq分治,第三维cdq分治,第四维树状数组,找到满足j(x,y,z,w)<=i(x,y,z,w)的j,给i统计 ...

  7. Codeforces 1175G - Yet Another Partiton Problem(李超线段树)

    Codeforces 题面传送门 & 洛谷题面传送门 这是一道李超线段树的毒瘤题. 首先我们可以想到一个非常 trivial 的 DP:\(dp_{i,j}\)​ 表示前 \(i\)​ 个数划 ...

  8. Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)

    听说正解是啥 set启发式合并+维护凸包+二分 根本不会啊 , 只会 李超线段树合并 啦 ... 题意 给你一颗有 \(n\) 个点的树 , 每个节点有两个权值 \(a_i, b_i\) . 从 \( ...

  9. 【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交

    4515: [Sdoi2016]游戏 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 304  Solved: 129[Submit][Status][ ...

随机推荐

  1. 用jquery实现toast的原理

    function toast(mess){ var str='<div class="mess"><span></span></div&g ...

  2. ispoweroftwo 判断2的次幂

    首先结果是: public bool IsPowerOfTwo(int n) { if(n<1) return false;//2的次幂一定大于0 return ((n & (n -1) ...

  3. 事件,使用.net自带委托EventHandler

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. NuGet套件还原步骤(以vs2012为例)

    下载别人的范例,出现由于Nuget套件不存在而无法启动时: 效果如下图: 步骤如下: 1.点击 项目->启用NuGet程序包还原 2.点击下图中的是 3.点击下图中的确定 4.效果如图: . 5 ...

  5. Python解决八皇后问题的代码【解读】

    八皇后问题 来自于西方象棋(现在叫 国际象棋,英文chess),详情可见百度百科. 在西方象棋中,有一种叫做皇后的棋子,在棋盘上,如果双方的皇后在同一行.同一列或同一斜线上,就会互相攻击. 八皇后问题 ...

  6. python基础--shutil模块

    shutil模块提供了大量的文件的高级操作. 特别针对文件拷贝和删除,主要功能为目录和文件操作以及压缩操作.对单个文件的操作也可参见os模块. 注意 即便是更高级别的文件复制函数(shutil.cop ...

  7. java基础71 XML解析中的【DOM和SAX解析工具】相关知识点(网页知识)

    本文知识点(目录):本文下面的“实例及附录”全是DOM解析的相关内容 1.xml解析的含义    2.XML的解析方式    3.xml的解析工具    4.XML的解析原理    5.实例    6 ...

  8. python之uinttest单元测试框架

    unittest,是python中针对单元测试的一个测试框架 相当于python版的junit 简单举个例子: 如图,使用时,测试类需要继承单元测试TestCase这个类 必须要有setUp()和te ...

  9. No.4 selenium学习之路之iframe

    查看iframe: 1.top window ——可以直接进行定位

  10. luogu P3393 逃离僵尸岛

    luoguP3393逃离_僵尸岛_ 一道洛谷不知道哪门子月赛的题 可以用此题来练习最短路算法 SPFA和dijkstra的练习题(关于Floyed,他死了 思路: 本题是最短路板子. 首先就是建立虚点 ...