简要题意

给定 \(n\) 个左闭右开的区间 \(A_i = [L_i, R_i)\),其中 \(0\le L_i < R_i \le x\),你可以自由选择 \(k\) 个长度为 \(m\) 左闭右开的区间 \(B_j = [l_j, r_j)\) 使得 \(0\le l_j<r_j\le x\)。区间长度定义为内部整点个数。接下来给每个 \(A\) 中的区间 \(A_i\) 分配唯一的一个 \(B\) 中的区间 \(B_{p_i}\)(\(B\) 中区间可以重复使用),你需要最大化 \(\sum_i \operatorname{len}\left([1, x)\backslash(A_i\cup B_{p_i})\right)\)。

数据范围:\(1\le k\le n\le 2000,1\le m\le x\le 10^9\)。

题解

非常好题。

首先考虑如果已经确定了 \(B\),那么如何确定 \(p_i\),也就是如何给 \(A\) 中元素分配 \(B\) 中区间。注意到我们需要最大化的是 \(A_i\cap B_{p_i}\) 的 总长度,而 \(B_i\) 长度都相同。那么显然的,\(A_i\) 和 \(B_{p_i}\) 中点越接近就越好。所以其实分配 \(B_i\) 的过程是很优美的:把 \(A\) 按中点坐标排序,那么一定是将其划分为不超过 \(k\) 个连续段,其中每个段内对应的 \(B\) 区间相同。

这样我们很容易设计出一个 2D/1D DP。设 \(f_{i,j}\) 表示前 \(i\) 个区间划分成 \(j\) 段最大的区间交的长度和。记 \(g_{l, r}\) 表示 \(A_{l\dots r}\) 的所有区间如果分为一组,选取的 \(B\) 区间最优时,区间交的长度和。那么转移形如 \(f_{i, j} = \max\limits_{k=1}^{i}f_{k-1, j-1}+g_{k,i}\)。

那么接下来就有两个问题:1. 怎么求出 \(g\);2. 怎么快速转移 \(f\)。

解决第一个问题需要比较好的直觉。首先,可能的区间有 \(\Theta(x)\) 种,这是不可接受的。第一反应是有没有什么公式或者高妙手段能直接计算出区间位置,但是找了一段时间并没有。那么考虑可行的区间。假设一个候选区间的左端点不是任何一个段内 \(A\) 区间的左端点,右端点也不是任何一个段内区间的右端点,那么把它向左或向右移动一定至少有一个不劣。所以可能的最优区间只有 \(\Theta(n)\) 种。这时候如果预处理出一些前缀和,可以 \(\Theta(n^3)\) 算出所有 \(g\) 的值。这显然不够。对 \(g\) 的一些洞察告诉我们,记 \(g_{l,r}\) 的决策点为 \(t_{l,r}\),则 \(t_{l-1,r}\le t_{l,r}\le t_{l,r+1}\)。直接运用决策单调性优化做到 \(\Theta(n^2)\)。

第二个问题比较好解决。首先注意到记录 \(j\) 是为了限制区间不超过 \(k\) 个,于是直接上一个 wqs 二分(aliens trick)即可做到平方 \(\log\)。另一种方法则是注意到 \(g\) 满足四边形不等式(这其实是根据 DP 方程的形状猜到的),那么 \(f\) 具有决策单调性,于是就做到了 \(\Theta(n^2)\)。

我用了 wqs 二分。

代码

// Author: kyEEcccccc

#include <bits/stdc++.h>

using namespace std;

using LL = long long;
using ULL = unsigned long long; #define F(i, l, r) for (int i = (l); i <= (r); ++i)
#define FF(i, r, l) for (int i = (r); i >= (l); --i)
#define MAX(a, b) ((a) = max(a, b))
#define MIN(a, b) ((a) = min(a, b))
#define SZ(a) ((int)((a).size()) - 1) const int N = 2005; int n, k, x, m, nn;
struct Seg { int l, r; } a[N];
vector<int> p;
int opt[N][N];
LL f[N], g[N][N], w[N << 1][N];
int h[N]; LL intersect(Seg a, Seg b)
{
if (a.l > b.l) swap(a, b);
if (a.r <= b.l) return 0;
return min(a.r, b.r) - b.l;
} void compute_g(void)
{
F(i, 1, nn) F(j, 1, n)
w[i][j] = w[i][j - 1] + intersect({p[i], p[i] + m}, a[j]);
FF(d, n - 1, 0) F(l, 1, n - d)
{
int r = l + d;
int pl = l == 1 ? 1 : opt[l - 1][r],
pr = r == n ? nn : opt[l][r + 1];
// cerr << l << ' ' << r << ' ' << pl << ' ' << pr << '\n';
// pl = 1, pr = nn;
g[l][r] = LLONG_MIN / 2;
F(i, pl, pr)
{
if (g[l][r] < w[i][r] - w[i][l - 1])
{
opt[l][r] = i;
g[l][r] = w[i][r] - w[i][l - 1];
}
}
}
} pair<int, LL> compute(LL slp)
{
F(i, 1, n)
{
pair<LL, int> fr = {g[1][i], 0};
F(j, 1, i - 1) MAX(fr, make_pair(f[j] + g[j + 1][i], -h[j]));
f[i] = fr.first - slp; h[i] = -fr.second + 1;
}
return {h[n], f[n]};
} signed main(void)
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(nullptr); cin >> n >> k >> x >> m;
LL ans = (LL)x * n - (LL)m * n;
F(i, 1, n)
{
cin >> a[i].l >> a[i].r;
ans -= a[i].r - a[i].l;
p.push_back(a[i].l + m > x ? x - m : a[i].l);
p.push_back(a[i].r - m < 0 ? 0 : a[i].r - m);
}
sort(a + 1, a + n + 1, [] (Seg a, Seg b)
{ return a.l + a.r < b.l + b.r; });
sort(p.begin(), p.end());
p.resize(unique(p.begin(), p.end()) - p.begin());
nn = p.size();
p.insert(p.begin(), 0); compute_g(); LL cl = 0, cr = 2000000000000LL, ca, cc;
while (cl <= cr)
{
LL cm = (cl + cr) >> 1;
pair<int, LL> res = compute(cm);
if (res.first <= k)
ca = res.second, cc = cm, cr = cm - 1;
else cl = cm + 1;
}
cout << ca + ans + cc * k << '\n'; return 0;
}

CF1832F Zombies的更多相关文章

  1. TOJ 4120 Zombies VS Plants

    链接:http://acm.tju.edu.cn/toj/showp4120.html 4120.   Zombies VS Plants Time Limit: 1.0 Seconds   Memo ...

  2. ZOJ 4062 Plants vs. Zombies(二分答案)

    题目链接:Plants vs. Zombies 题意:从1到n每个位置一棵植物,植物每浇水一次,增加ai高度.人的初始位置为0,人每次能往左或往右走一步,走到哪个位置就浇水一次.求m步走完后最低高度的 ...

  3. Plants vs. Zombies(二分好题+思维)

    Plants vs. Zombies http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5819 BaoBao and DreamG ...

  4. IOS性能调优系列:使用Zombies动态分析内存中的僵尸对象

    硬广:<IOS性能调优系列>第四篇,预计会有二十多篇,持续更新,欢迎关注. 前两篇<IOS性能调优系列:Analyze静态分析>.<IOS性能调优系列:使用Instrum ...

  5. zoj4062 Plants vs. Zombies 二分+模拟(贪心的思维)

    题目传送门 题目大意:有n个植物排成一排,标号为1-n,每株植物有自己的生长速度ai,每对植物浇一次水,该株植物就长高ai,现在机器人从第0个格子出发,每次走一步,不能停留,每一步浇一次水,总共可以走 ...

  6. uva 12452 Plants vs. Zombies HD SP (树DP)

    Problem I: Plants vs. Zombies HD Super Pro Plants versus Zombies HD Super Pro is a game played not a ...

  7. ACM_Plants vs. Zombies(一元一次方程)

    Plants vs. Zombies Time Limit: 2000/1000ms (Java/Others) Problem Description: There is a zombie on y ...

  8. ZOJ 4062 - Plants vs. Zombies - [二分+贪心][2018 ACM-ICPC Asia Qingdao Regional Problem E]

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4062 题意: 现在在一条 $x$ 轴上玩植物大战僵尸,有 $n$ ...

  9. 2018ICPC青岛 E - Plants vs. Zombies (二分+模拟)

    ZOJ - 4062 题意:有n个植物排成一排,按顺序植物的编号是1-n,每个植物都有一个生长速率,有一个机器人,机器人可以走m步,每走一步,这个机器人就会浇一次水,浇一次水那个植物就会长 自身的生长 ...

  10. ZOJ4062 Plants vs. Zombies(二分+贪心)

    题目链接:传送门 题目大意: 有n棵植物依次放在1-n,机器人从0出发浇水,每棵植物被浇水时di += ai,求浇m次水后min{di|1 ≤ i ≤ n}的最大值.(浇水时必须往左或往右走一步,落脚 ...

随机推荐

  1. NEFU高级程序设计-期末复习习题组

    1. 用链表实现单词序列倒序输出 题目 用链表实现单词序列倒序输出.与以往不同,请考虑采用一种完全的动态分配方式! 为降低难度,"仁慈"的我已经给出了输出和释放的代码,你只要写出创 ...

  2. python入门教程之十函数

    函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创建函数,这 ...

  3. mysql锁及锁出现总结

    转载请注明出处: 1.按锁粒度分类: 行锁:锁某行数据,锁粒度最小,并发度高:: 行锁是指加锁的时候锁住的是表的某一行或多行记录,多个事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问 ...

  4. vue条件判断循环

    条件判断 v-if <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  5. Java并发(二)----初次使用多线程并行提高效率

    1.并行 并行代表充分利用多核 cpu 的优势,提高运行效率. 想象下面的场景,执行 3 个计算,最后将计算结果汇总. 计算 1 花费 10 ms ​ 计算 2 花费 11 ms ​ 计算 3 花费 ...

  6. C 语言版线程池

    一.初始线程池 1.1 何为线程池? 我们先来打个比方,线程池就好像一个工具箱,我们每次需要拧螺丝的时候都要从工具箱里面取出一个螺丝刀来.有时候需要取出一个来拧,有时候螺丝多的时候需要多个人取出多个来 ...

  7. c/c++零基础坐牢第一天

    c/c++从入门到入土(1) 开始时间2023-04-12 22:37:21 结束时间2023-04-13 00:02:26 前言:恭喜大家打开信息时代的大门,每个时代都有代表性的炫酷技能:原始时代的 ...

  8. python pyinstaller库

    简要 pyinstaller模块主要用于python代码打包成exe程序直接使用,这样在其它电脑上即使没有python环境也是可以运行的. 用法 一.安装 pyinstaller属于第三方库,因此在使 ...

  9. 【介绍】.NET新加特性介绍

    ​ 简介 当下的.Net新版本引进了几种新特性,包括全局命名空间引用.可空引用类型和顶级语句.这些特性在一定程度上改善了 .NET 平台的开发效率, 对于短小精干的小程序,这些新的特性无疑可以把开发效 ...

  10. 聊一聊 GDB 调试程序时的几个实用命令

    一:背景 1. 讲故事 用惯了宇宙第一的 Visual Studio 再用其他的开发工具还是有一点不习惯,不习惯在于想用的命令或者面板找不到,总的来说还是各有千秋吧,今天我们来聊一下几个在调试中比较实 ...