国际惯例的题面:

我们考虑大力DP。
首先重新定义代价为:1e13*选择数量-(总高度+总补偿)。这样我们只需要一个long long就能维护。
然后重新定义高度为heighti - i,这样我们能选择高度相同的点,同时可以把无论如何也不会被选择的点扔掉(这样他们的高度<0)。
之后就是转移,我们枚举i前面的被选择的点j,我们要满足的东西有:hj<=hi。
考虑我们再次选择一个点会产生怎样的代价,显然最终的答案一定是一个阶梯状的东西,所以我们选择了i之后之后所有点的高度相对于仅选择j都会上升(hi-hj)。
于是我们就可以转移了,fi=max{fj+(hi-hj)*(n-i+1)}(hj<=hi)+cost[i],cost[i]为单点价值减去选i的补偿代价。于是你可以写对拍用的n^2暴力了。
仔细观察这个转移方程,显然是一个可斜率优化的方程,我们可以把hi当成x,把fi当成j,把(n-i+1)当成a,把1当成b,这样最优答案就是ax+by的形式了。
因为hi不满足单调性,所以我们需要set维护凸包
考虑到我们还有hj<=hi的限制,所以需要再套一层cdq分治......
注意:
cdq分治在排序的时候不能只排单一关键字,需要做双关键字排序,否则会导致一些能更新的东西无法更新。
然后发现你这么写并不能AC,因为常数太大......
代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#include<cmath>
#include<vector>
#define debug cout
typedef long long int lli;
using namespace std;
const int maxn=1e5+1e2;
const lli mul = 1e13+1e10; namespace Convex {
int cmp; // 0 compare x , 1 compare slope .
struct Point {
lli x,y;
long double slop;
friend bool operator < (const Point &a,const Point &b) {
if( !cmp ) return a.x != b.x ? a.x < b.x : a.y < b.y;
return a.slop > b.slop;
}
friend Point operator - (const Point &a,const Point &b) {
return (Point){a.x-b.x,a.y-b.y};
}
friend long double operator * (const Point &a,const Point &b) {
return (long double)a.x * b.y - (long double)b.x * a.y;
}
inline lli calc(lli a,lli b) const {
return a * x + b * y;
}
};
set<Point> st; inline void Pop_right(set<Point>::iterator nxt,const Point &p) {
set<Point>::iterator lst;
while() {
nxt = st.lower_bound(p);
lst = nxt , ++nxt;
if( nxt == st.end() ) return;
if( lst->x == p.x ) {
if( p.y > lst->y ) st.erase(lst);
else break;
}
else {
if( (*lst-p) * (*nxt-*lst) < ) return;
st.erase(lst);
}
}
}
inline void Pop_left(set<Point>::iterator prv,const Point &p) {
set<Point>::iterator lst;
prv = st.lower_bound(p) , --prv;
if( prv == st.begin() && prv->x == p.x ) return void(st.erase(prv));
while(prv!=st.begin()) {
prv = st.lower_bound(p) , --prv;
lst = prv , --prv;
if( p.x == lst->x ) {
if( p.y > lst->y ) st.erase(lst);
else break;
continue;
}
else {
if( (*lst-*prv) * (p-*lst) < ) break;
st.erase(lst);
}
}
}
inline bool fail(const Point &p) {
set<Point>::iterator it = st.lower_bound((Point){p.x,,});
if( it != st.end() && it->x == p.x ) {
if( it->y >= p.y ) return ; // p is useless at all .
else return ; // p must be on convex .
}
if( it != st.end() && it != st.begin() ) {
set<Point>::iterator prv = it; --prv;
if( ( p - *prv ) * (*it - p ) > ) return ;
}
return ;
}
inline void insert(const Point &p) {
cmp = ;
if( fail(p) ) return;
set<Point>::iterator prv,nxt,lst=st.lower_bound(p);
if(lst!=st.begin()) Pop_left(--lst,p);
lst=st.lower_bound(p);
if(lst!=st.end()) Pop_right(lst,p);
st.insert(p) , lst = st.find(p);
if(lst!=st.begin()) {
prv = lst , --prv;
Point x = *prv;
x.slop = (long double)( p.y - x.y ) / ( p.x - x.x );
st.erase(prv) , st.insert(x);
}
nxt = lst = st.find(p) , ++nxt;
if(nxt!=st.end()) {
Point x = p , n = *nxt;
x.slop = (long double)( n.y - x.y ) / ( n.x - x.x );
st.erase(lst) , st.insert(x);
} else {
Point x = p;
x.slop = -1e18;
st.erase(lst) , st.insert(x);
}
}
inline lli query(const lli &k) {
cmp = ;
set<Point>::iterator it = st.lower_bound((Point){,,(long double)-k}); // it can't be st.end() if st isn't empty .
if( it==st.end() ) return ;
lli ret = it->calc(k,);
if( it != st.begin() ) {
--it;
ret = max( ret , it->calc(k,) );
}
++it; if( ++it!=st.end() ) ret = max( ret , it->calc(k,) );
return ret;
}
inline void clear() {
st.clear() , cmp = ;
}
} lli ina[maxn],inb[maxn],f[maxn],cst[maxn],ans,add; // f[id] .
bool isl[maxn];
int n; int cmp; // 0 compare height , 1 compare id .
struct Node {
lli hei,id;
friend bool operator < (const Node &a,const Node &b) {
if( cmp ) return a.id != b.id ? a.id < b.id : a.hei < b.hei;
else return a.hei != b.hei ? a.hei < b.hei : a.id < b.id;
}
}ns[maxn]; vector<Node> vec; inline void solve(vector<Node> &vec) {
if( vec.size() <= ) {
if( vec.size() ) f[vec[].id] = max( f[vec[].id] , cst[vec[].id] );
return;
}
vector<Node> vl,vr;
const unsigned mid = vec.size() >> ;
for(unsigned i=;i<mid;i++) vl.push_back(vec[i]);
for(unsigned i=mid;i<vec.size();i++) vr.push_back(vec[i]);
solve(vl);
for(unsigned i=;i<vl.size();i++) isl[vl[i].id] = ;
for(unsigned i=;i<vr.size();i++) isl[vr[i].id] = ;
cmp = , sort(vec.begin(),vec.end()) , Convex::clear();
for(unsigned i=;i<vec.size();i++) {
if( isl[vec[i].id] ) {
Convex::insert((Convex::Point){vec[i].hei,f[vec[i].id],});
} else {
f[vec[i].id] = max( f[vec[i].id] , cst[vec[i].id] + Convex::query(n-vec[i].id+));
}
}
solve(vr);
} int main() {
static lli sel,lst;
scanf("%d",&n) , add = (lli) n * ( n + ) >> ;
for(int i=;i<=n;i++) scanf("%lld",ina+i) , ina[i] -= i;
for(int i=;i<=n;i++) {
scanf("%lld",inb+i);
if( ina[i] >= ) {
cst[i] = mul - inb[i] - ina[i] * ( n - i + ) ,
vec.push_back((Node){ina[i],i});
}
}
cmp = , sort(vec.begin(),vec.end());
solve(vec);
for(int i=;i<=n;i++) ans = max( ans , f[i] );
ans -= add;
sel = ( ans + mul ) / mul;
lst = mul * sel - ans;
printf("%lld %lld\n",sel,lst);
return ;
}

另外这个东西其实不用平衡树维护凸包,如果你外层分治位置,内层分治height的话,height就会有序,这样只需要写一个普通凸包就好了......
在BZOJ上只有这样才能AC......//QAQ
代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define debug cout
typedef long long int lli;
typedef long double ldb;
using namespace std;
const int maxn=1e5+1e2;
const lli mul = 1e13 + 1e10; struct Convex {
struct Point {
lli x,y;
friend Point operator - (const Point &a,const Point &b) {
return (Point){a.x-b.x,a.y-b.y};
}
friend ldb operator * (const Point &a,const Point &b) {
return (ldb)a.x*b.y - (ldb)a.y*b.x;
}
friend lli operator ^ (const Point &a,const Point &b) {
return a.x * b.x + a.y * b.y;
}
}ps[maxn];
int top;
inline void push(const Point &p) {
while( top > ) {
if( p.x == ps[top].x && p.y > ps[top].y ) --top;
else if( ( ps[top] - ps[top-] ) * ( p - ps[top] ) > ) --top;
else break;
}
if( top == && p.x == ps[top].x && p.y > ps[top].y ) --top;
if( !top || p.x != ps[top].x ) ps[++top] = p;
}
inline lli query(const Point &p) {
int l = , r = top , lmid , rmid;
while( r > l + ) {
lmid = ( l + l + r ) / , rmid = ( l + r + r ) / ;
if( ( p ^ ps[lmid] ) < ( p ^ ps[rmid] ) ) l = lmid;
else r = rmid;
}
lli ret = ;
for(int i=l;i<=r;i++) ret = max( ret , p ^ ps[i] );
return ret;
}
inline void clear() {
top = ;
}
}con; lli ina[maxn],inb[maxn],f[maxn],cst[maxn],ans,add; // f[id] .
bool isl[maxn];
int n; int cmp; // 0 compare height , 1 compare id .
struct Node {
lli hei,id;
friend bool operator < (const Node &a,const Node &b) {
if( cmp ) return a.id != b.id ? a.id < b.id : a.hei < b.hei;
else return a.hei != b.hei ? a.hei < b.hei : a.id < b.id;
}
}ns[maxn]; vector<Node> vec; inline void solve(vector<Node> &vec) {
if( vec.size() <= ) {
if( vec.size() ) f[vec[].id] = max( f[vec[].id] , cst[vec[].id] );
return;
}
vector<Node> vl,vr;
const unsigned mid = vec.size() >> ;
for(unsigned i=;i<mid;i++) vl.push_back(vec[i]);
for(unsigned i=mid;i<vec.size();i++) vr.push_back(vec[i]);
solve(vl);
for(unsigned i=;i<vl.size();i++) isl[vl[i].id] = ;
for(unsigned i=;i<vr.size();i++) isl[vr[i].id] = ;
cmp = , sort(vec.begin(),vec.end()) , con.clear();
for(unsigned i=;i<vec.size();i++) {
if( isl[vec[i].id] ) {
con.push((Convex::Point){vec[i].hei,f[vec[i].id]});
} else {
f[vec[i].id] = max( f[vec[i].id] , cst[vec[i].id] + con.query((Convex::Point){n-vec[i].id+,}));
}
}
solve(vr);
} int main() {
static lli sel,lst;
scanf("%d",&n) , add = (lli) n * ( n + ) >> ;
for(int i=;i<=n;i++) scanf("%lld",ina+i) , ina[i] -= i;
for(int i=;i<=n;i++) {
scanf("%lld",inb+i);
if( ina[i] >= ) {
cst[i] = mul - inb[i] - ina[i] * ( n - i + ) ,
vec.push_back((Node){ina[i],i});
}
}
cmp = , sort(vec.begin(),vec.end());
solve(vec);
for(int i=;i<=n;i++) ans = max( ans , f[i] );
ans -= add;
sel = ( ans + mul ) / mul;
lst = mul * sel - ans;
printf("%lld %lld\n",sel,lst);
return ;
}

Bzoj2149拆迁队:cdq分治 凸包的更多相关文章

  1. bzoj2149拆迁队 斜率优化dp+分治

    2149: 拆迁队 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 397  Solved: 177[Submit][Status][Discuss] ...

  2. BZOJ2961: 共点圆(CDQ分治+凸包)

    题面 传送门 题解 这题解法真是多啊--据说可以圆反演转化为动态插入半平面并判断给定点是否在半平面交中,或者化一下改成给定点判断是否所有点都在某一个半平面内-- 鉴于圆反演我也不会,这里讲一下直接推的 ...

  3. [BZOJ2961] 共点圆 [cdq分治+凸包]

    题面 BZOJ传送门 思路 首先考虑一个点$(x_0,y_0)$什么时候在一个圆$(x_1,y_1,\sqrt{x_1^2+y_1^2})$内 显然有:$x_1^2+y_1^2\geq (x_0-x_ ...

  4. BZOJ2149 : 拆迁队

    设$c[i]=g[i]+\frac{i(i+1)}{2}-a[i]\times i-a[i]$,$d[i]=a[i]-i$ $f[i]$表示以$i$为结尾最多保留多少个建筑,则 $f[i]=\max( ...

  5. BZOJ 1492 货币兑换 cdq分治或平衡树维护凸包

    题意:链接 方法:cdq分治或平衡树维护凸包 解析: 这道题我拒绝写平衡树的题解,我仅仅想说splay不要写挂,insert边界条件不要忘.del点的时候不要脑抽d错.有想写平衡树的去看140142或 ...

  6. BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)

    BZOJ1492:[NOI2007]货币兑换 题目传送门 [问题描述] 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券).每个持有金券的 ...

  7. BZOJ 1492 [NOI2007]货币兑换Cash (CDQ分治/splay 维护凸包)

    题目大意:太长了略 splay调了两天一直WA弃疗了 首先,我们可以猜一个贪心,如果买/卖,就一定都买/卖掉,否则不买/卖 反正货币的行情都是已知的,没有任何风险,所以肯定要选择最最最优的方案了 容易 ...

  8. hdu5127 Dogs' Candies CDQ分治 动态凸包

    传送门 题意 有三种操作 加入一个二元组\((x,y)\) 删除一个二元组\((x,y)\) 给出一个二元组\((a,b)\),问\(ax+by\)的最大值 题解 \(z=ax+by \Rightar ...

  9. bzoj2961 共点圆 (CDQ分治, 凸包)

    /* 可以发现可行的圆心相对于我们要查询的点是在一个半平面上, 然后我们要做的就是动态维护凸壳然后用这个半平面去切它 看看是否是在合法的那一面 然后cdq分治就可以了 代码基本是抄的, */ #inc ...

随机推荐

  1. Oracle笔记 - unfinished

    1. plsql查看xmltype字段的xml格式时,出现中文乱码问题,可通过该字段.getClobVal():查询到的xml将是中文不乱码的. 2. extract函数查询xml某节点下的所有节点, ...

  2. Spark记录-spark编程介绍

    Spark核心编程 Spark 核心是整个项目的基础.它提供了分布式任务调度,调度和基本的 I/O 功能.Spark 使用一种称为RDD(弹性分布式数据集)一个专门的基础数据结构,是整个机器分区数据的 ...

  3. 【DS】排序算法之快速排序(Quick Sort)

    一.算法思想 快速排序,顾名思义,效率比较于其他算法,效率比较高.<算法导论>也专门对其进行讲解.其算法设计使用分治思想,如下: 1)从数组A[p...r]中选择一个元素,将数组划分成两个 ...

  4. Dubbo学习笔记4:服务消费端泛化调用与异步调用

    本文借用dubbo.learn的Dubbo API方式来解释原理. 服务消费端泛化调用 前面我们讲解到,基于Spring和基于Dubbo API方式搭建简单的分布式系统时,服务消费端引入了一个SDK二 ...

  5. SPOJ 8222 NSUBSTR - Substrings

    http://www.spoj.com/problems/NSUBSTR/ 题意: F(x)定义为字符串S中所有长度为x的子串重复出现的最大次数 输出F[1]~F[len(S)] 用字符串S构建后缀自 ...

  6. [QuickRoR]Ruby on Rails开发环境安装

    1.Setup Ruby on Rails2.Test Web App3.Create the First Web App 1.Setup Ruby on Rails1) Download rubyi ...

  7. 2016-2017-2 20155309 南皓芯java第六周学习总结

    教材内容详解 这一次主要学习的是第十章与第十一章的内容.主要讲述了串流,字符处理和线程以及并行API. 输入输出 串流:Java中的数据有来源(source)和目的地(destination),衔接两 ...

  8. 开放通用Api,总有你喜欢的

    接口文档 目录 通用 更新记录 接口列表 一.福彩-双色球接口 指定期号中奖号码 最新中奖号码信息 获取双色球中奖信息列表 二.节假日及万年历 指定日期的节假日及万年历信息 指定多个日期的节假日及万年 ...

  9. js深复制

    一般来讲深复制主要是为了复制js对象中的引用类型,引用类型在普通的赋值操作下相当于是引用,修改复制对象也会影响原对象,简单的方法的话可以使用JSON.parse(JSON.stringify(obj) ...

  10. /etc/sysctl.conf 调优 & 优化Linux内核参数

    from: http://apps.hi.baidu.com/share/detail/15652067 http://keyknight.blog.163.com/blog/static/36637 ...