Description:

lanxisi带领着他的拆迁队来整治一个街道。这个街道由N个旧房子组成,从左到右编号为1..N。每个旧房子i有一个正整数的美观度Ai。
  lanxisi希望整个街道从左到右美观度严格递增,也就是保证 Ai<Aj(i<j) Ai。但是旧的街道明显不符合这个要求,于是lanxisi希望拆迁一些旧房子并在原地建立新房子来满足这一要求。但是与很多拆迁队一样,很多钉子户拒绝拆迁。所以lanxisi希望能保留最多的旧房子来满足某些钉子户,当然,保留一个旧房子需要给房子主人Bi的赔偿金。最后,总花费=整治好以后所有房子美观度之和+赔偿金之和。新的美观值也都必须是正整数。
  现在,请你求出lanxisi最多能保留多少旧房子和整治这个街道所需要的最少总花费(当然是在保留旧房子最多这个前提下的)。
 1<=N<=100000,0<=Ai,Bi<=100000000。

:题解:

先思考最朴素的O(n^2)dp是如何运作的。

fi f_i是以i结尾最长不下降子序列的长度。
si s_i是以i结尾的最小总花费。

fi=max(fi+1)j<i,a[j]<a[i],a[j]−j<=a[i]−i) f_{i}=max(f_{i}+1)j
si=min(sj+…)(j<i,a[j]<a[i],a[j]−j<=a[i]−i,f[i]=f[j]+1) s_{i}=min(s_{j}+…)(j

如果有:
j<k,a[j]−j<=a[k]−k j
那么一定有:
a[j]<a[k] a[j]

所以可以去掉一个条件。

这样就可以可以用O(n log n)的时间按照a[i]-i为关键字dp出f。

接着按f分层dp。

打省略号的部分可以化成三部分:
1.和j有关的部分
2.和i有关的部分
3.(a[j]-j)*i

在同一层中,如果序号j递增,则a[j]-j递减,不然它们就不会在同一层。

所以满足斜率优化形式。

但是并没有这么简单。

注意条件除了a[j]-j<=a[i]-i,还有 j<i j

在分层后,序号并不是递增,高层的序号可能比低层小,而且a[j]-j同样只是在同一层内有序,不同层的大小关系无法判断。

简化问题后可以看作对一层的连续的一段j求
min(sj+(a[j]−j)∗i) min(s_{j}+(a[j]-j)*i)

到这里可以同线段树的分治思想来拆分询问。

对同一层建个线段树,每个点存这个点所代表的区间的j的单调栈。

因为线段树只有 log log层,每层最多n个,所以总共是 O(nlogn) O(n log n)。

接着把询问利用线段树拆成 log log段,每一段二分又是 log log,总复杂度是 O(nlog2n) O(n log^2 n)。

Code:

#include<cstdio>
#include<algorithm>
#define ll long long
#define ld long double
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
#define fd(i, x, y) for(ll i = x; i >= y; i --)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;const ll N = 1e5 + 5;ll n, a[N], b[N], f[N], l[N], ml;
ll s[N], g[N], h[N];
ll final[N], next[N], to[N], tot;
ll st, en, ans;ld ji(ll k, ll b, ll l, ll r) {return (ld) (r - b) / (ld)(k - l);
}
ld jj(ll x, ll y) {return ji(h[x], g[x], h[y], g[y]);
}int d[N * 30], d0, z[N];
struct tree {int l, r;
} t[N * 4];void Build(int i, int x, int y) {t[i].l = d0 + 1; t[i].r = d0;fo(j, x, y) {while(t[i].l < t[i].r && jj(d[t[i].r - 1], d[t[i].r]) > jj(d[t[i].r], z[j]))t[i].r --;d[++ t[i].r] = z[j];}d0 = t[i].r;if(x == y) return;int m = x + y >> 1;Build(i + i, x, m); Build(i + i + 1, m + 1, y);
}ll xx;ll find(int i, int x, int y, int l, int r) {if(l > r) return 1e18;if(x == l && y == r) {int as = t[i].l;for(int p = t[i].l + 1, q = t[i].r; p <= q; ) {int m = p + q >> 1;if(jj(d[m - 1], d[m]) <= xx) as = m, p = m + 1; else q = m - 1; }return h[d[as]] * xx + g[d[as]];}int m = x + y >> 1;if(r <= m) return find(i + i, x, m, l, r);if(l > m) return find(i + i + 1, m + 1, y, l, r);ll p = find(i + i, x, m, l, m), q = find(i + i + 1, m + 1, y, m + 1, r);return min(p, q);
}int main() {scanf("%lld", &n);fo(i, 1, n) scanf("%lld", &a[i]);fo(i, 1, n) scanf("%lld", &b[i]);ml = 0; l[0] = 0;fo(i, 1, n) {if(a[i] - i < 0) {f[i] = 0; continue;}for(ll L = 1, r = ml; L <= r; ) {ll m = L + r >> 1;if(l[m] <= a[i] - i) f[i] = m, L = m + 1; else r = m - 1;}f[i] ++;if(f[i] > ml) l[++ ml] = a[i] - i;l[f[i]] = min(l[f[i]], a[i] - i);}fd(i, n, 1) next[++ tot] = final[f[i]], to[tot] = i, final[f[i]] = tot;fo(l, 1, ml) {z[0] = 0; d0 = 0;for(ll y = final[l - 1]; y; y = next[y])z[++ z[0]] = to[y];if(z[0]) Build(1, 1, z[0]);int st = 1, en = 0;for(ll ii = final[l]; ii; ii = next[ii]) {ll x = to[ii]; xx = x;while(en < z[0] && z[en + 1] < x) en ++;while(st <= en && a[z[st]] - z[st] > a[x] - x) st ++;s[x] = (a[x] - x >= 0 && l == 1) ? (b[x] + x * (x - 1) / 2) : 1e18;ll p = find(1, 1, z[0], st, en) + x * (x - 1) / 2 + b[x];s[x] = min(s[x], p);g[x] = s[x] - a[x] * x + (x + 1) * x / 2;h[x] = a[x] - x;}}ans = 1e18;fo(i, 1, n) if(f[i] == ml)ans = min(ans, s[i] + (n - i + 1) * a[i] + (n - i) * (n - i + 1) / 2);printf("%lld %lld", ml, ans);
}

【2011集训队出题】拆迁队相关推荐

  1. 【2011集训队出题】跳跳棋

    [2011集训队出题]跳跳棋 Time Limits: 1000 ms Memory Limits: 128000 KB Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点 ...

  2. JZOJ 1980. 【2011集训队出题】Construct

    Description 随着改革开放的深入推进-- 小T家要拆迁了-- 当对未来生活充满美好憧憬的小T看到拆迁协议书的时候,小T从一位大好的社会主义青年变成了绝望的钉子户. 由于小T的家位于市中心,拆 ...

  3. bzoj2144 [2011集训队出题] 跳跳棋 倍增 lca

    Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把 ...

  4. [国家集训队2011]拆迁队nbsp;解题报告

    题目: http://cogs.pro/cogs/problem/problem.php?pid=1859 lanxisi带领着他的拆迁队来整治一个街道.这个街道由N个旧房子组成,从左到右编号为1.. ...

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

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

  6. 【分治+斜率优化】BZOJ2149拆迁队 CF660F Bear and Bowling 4

    BZOJ2149拆迁队 [题目] 原题地址 题目大意不想写. [题目分析] 斜率优化的dp是显然的,然后就是怎么维护的问题了. [解题思路] 这题显然就是一个斜率优化的dp,然后分治的时候维护一下凸壳 ...

  7. chrome游戏:“钉子户大战拆迁队(Guard NailHoushold)”和“The Fancynbs

    查看原文:http://www.hellonet8.com/214.html 上个月chrome OS发布的时候,chrome 8 用户可以通过web store下载程序,自己就好奇进去下了些东西耍会 ...

  8. chrome游戏:“钉子户大战拆迁队(Guard NailHoushold)”和“The Fancy Pants Adventure: World 2”...

    上个月chrome OS发布的时候,chrome 8 用户可以通过web store下载程序,自己就好奇进去下了些东西耍会.好多程序就是简简单单的一个网页,可用性不怎么样,所以基本都被我卸载了.现在还 ...

  9. 《C#妹妹和Objective-C阿姨对话录》(04)垃圾回收基础--拆迁队那点事

    C#妹妹:操作系统天天说控制内存空间价格,咋还这么高?我巨资购买的内存空间,后来发现竟然在硬盘上!虚拟内存!TMD! Objective-C阿姨:操作系统全靠卖内存空间挣钱呢,你说价格能会降么?你看看 ...

最新文章

  1. 莫比乌斯反演专题学习笔记
  2. java方法体逻辑不会写怎么办,想自己写框架?不会写Java注解可不行
  3. Go 语言基础(三) 之 函数
  4. JS正则表达式验证数字非常全
  5. 阅读之web应用安全
  6. linux中544进程,Linux基础--进程管理及其基本命令
  7. [蓝桥杯][2016年第七届真题]密码脱落(记忆化搜索)
  8. java调用kettle批量执行
  9. JQuery在循环中绑定事件的问题详解
  10. linux取反格式,linux基本命令总结(二)
  11. 如何新建一个keil工程 的详细步骤
  12. jdk 6u45 下载地址
  13. 典型相关分析(CCA)简述
  14. word公式编号问题
  15. NLP 的巨人肩膀(下):从 CoVe 到 BERT
  16. 华为员工待遇全面揭秘
  17. 为什么要面向对象编程?
  18. 【网络】正向代理和反向代理
  19. 沁恒蓝牙芯片CH57x系列学习与应用
  20. 用月壤实现太阳能发电,人类离「定居月球」又近一步 | 来自贝索斯蓝色起源...

热门文章

  1. 手机租赁分期上征信吗?
  2. 项目管理 : 冲突管理
  3. 对路径 的访问被拒绝
  4. linux查看docker版本,如何查看docker的版本号是多少
  5. BIOS dmi 信息获取
  6. 推动高校数字化转型发展 华云数据解锁智慧图书馆建设新方式
  7. 使用STM32在SPI模式下读写SD卡
  8. FLEX(Flipboard Explorer)简介
  9. 关于属性和字段的初步了解
  10. python dcf估值_估值方法梳理 把CFA二级书本中提及的企业估值方法在白板上全列了一遍。 一、 静心思考,绝对估值法(DCF、FCFF、FCFE、RI)... - 雪球...