*IX. P5896 [IOI2016]aliens

DP 优化方法大杂烩,详解 wqs 二分及其注意事项,斜率优化等其它 DP 优化方法。

**** 团队赛 T6,没想到是 IOI 原题。当时看出来要用 wqs 二分,但是我没学过(经常发生知道要用某种算法但是不会写的情况),因此最近学习了一下 wqs 二分。找题目练手的时候看到了这题,世 界 线 收 束。做题的过程中发现还要用到斜率优化,于是也学了一下。

这算是一道比较套路的题目,但套路并不意味这不是好题,毕竟我从中学到了 wqs 二分和斜率优化两种 DP 优化方法。说它套路其实也不太合适,因为 2016 年 wqs 二分还没有在 OI 界普及,甚至国外将其称之为 “Aliens’ Trick” 就是根据本题的名字而命名的,所以这个 idea 在当时应该比较新颖。


不妨对网格图的主对角线所经过的格子从左上到右下依次编号为 \(0,1,2,\cdots,m-1\)。显然,编号为 \(i\) 的格子在原网格图中的坐标为 \((i,i)\)。因为正方形的主对角线完全包含于网格图的主对角线,所以为了拍到一个点 \((r_i,c_i)\) 必然要拍到编号为 \(l_i,l_i+1,l_i+2,\cdots,r_i\) 的格子,其中 \(l_i=\min(r_i,c_i),r_i=\max(r_i,c_i)\)。因此,我们可以将题目转化为线段覆盖问题:现在有 \(n\) 条线段 \([l_i,r_i]\),我们要用最多 \(k\) 个区间 \([x_i,y_i]\) 去覆盖它们,使得每条线段至少被一个区间完全包含。即 \(\forall i,\exist j,s.t. [l_i,r_i]\in [x_j,y_j]\)。求以每个区间为对角线形成的所有正方形的面积并的最小值。接下来我们可以挖掘一些性质:

  • \(\textbf {Observation 1.}\) 如果两条线段 \(i,j\) 满足 \([l_i,r_i]\in [l_j,r_j]\),那么线段 \(i\) 对最终的答案没有影响。

    正确性显然。根据该性质,我们可以将所有线段按照左端点 \(l_i\) 从小到大为第一关键字,右端点 \(r_i\) 从大到小为第二关键字排序。然后依次遍历所有线段并记录右端点最大值 \(r\)。若当前线段 \(i\) 的右端点 \(r_i\leq r\),则忽略线段 \(i\);否则用 \(r_i\) 去更新 \(r\),即 \(r\gets r_i\)。最终所有没有被忽略的线段,一定满足左端点和右端点都单调递增。读者自证不难。

  • \(\mathbf{Observation\ 2.}\) 最终所选取的所有区间一定满足 \(x_i<x_{i+1},y_i<y_{i+1}\ (1\leq i<k)\)。

    读者自证不难。

  • \(\mathbf{Observation\ 3.}\) 设 \(F_i\) 为恰好选取 \(i\) 个区间时答案的最小值,那么 \(F_i\) 是一个下凸函数。

    读者自证不很难。感性理解一下即可,严格证明的话应该比较复杂。

有了上述性质,我们可以愉快地进行 DP 了:wqs 二分斜率 \(K\),然后设 \(f_i\) 表示覆盖第 \(i\) 条线段时的最小代价(线段按照左端点从小到大排序。根据性质 \(1\) 的结论,右端点也行,因为不影响线段之间的顺序)。显然有转移方程:

\[f_i=\min_{j=0}^{i-1}-K+\begin{cases}f_j+(y_i-x_{j+1}+1)^2-(y_j-x_{j+1}+1)^2&y_j\geq x_{j+1}\land j>0\\f_j+(y_i-x_{j+1}+1)^2&\mathrm{otherwise}\end{cases}
\]

这个分情况讨论很讨厌,尝试把它消灭掉:设 \(g_i=(y_i-x_{i+1}+1)^2[y_i\geq x_{i+1}\land i>0]\),那么转移方程变为 \(f_i=\min_{j=0}^{i-1}f_j+(y_i-x_{j+1}+1)^2-g_j-K\)。显然的斜率优化,但是我不会,所以多讲一点:拆开变成 \(f_i=\min_{j=1}^{i-1} f_j+(y_i+1)^2-2(y_i+1)x_{j+1}+x^2_{j+1}-g_j-K\)。先将所有 \(y_i\) 加上 \(1\)(不影响单调性),忽略掉 \(\min\) 再移移项,写成 \(Y=kX+b\) 的形式,\(f_j+x^2_{j+1}-g_j-K=2y_ix_{j+1}+(f_i-y_i^2)\)。那么 \(Y=f_j+x^2_{j+1}-g_j-K\),\(k=2y_i\),\(X=x_{j+1}\),\(b=f_i-y^2_i\)。将 \((X_j,Y_j)\) 看做一个点,因为 \(k\) 确定了,现在就要找使得 \(b\) 最小的 \((X_j,Y_j)\)(这样能使得 \(f_i\) 最小)。由于 \(k,X\) 都是单调递增的,所以单调队列维护下凸包即可。

具体地,记 \(k_{i,j}\) 为点 \((X_i,Y_i)\) 与 \((X_j,Y_j)\) 之间的斜率。首先将点 \(0\) 加入单调队列,接下来遍历从小到大每个位置 \(i\):

  • 若单调队列大小不小于 \(2\),设 \(a,b\) 分别为队首的第一个和第二个点,若 \(k_{a,b}\leq k=2y_i\) 则 \(b\) 一定不劣于 \(a\),弹出队首。重复该操作直到单调队列大小为 \(1\) 或 \(k_{a,b}>2y_i\)。
  • 此时队首 \(a\) 即为最优决策 \(j\),\(f_j\to f_i\) 转移并记录选择的区间个数。
  • 若单调队列大小不小于 \(2\),设 \(c,d\) 分别为队尾的倒数第二个和倒数第一个点;若 \(k_{c,d}\geq k_{d,i}\) 则 \(d\) 一定不在下凸包上,弹出队尾。重复该操作直到单调队列大小为 \(1\) 或 \(k_{c,d}<k_{d,i}\)。
  • 将点 \(i\) 加入单调队列。

我们需要求出在代价最小的前提下最少的区间个数。不妨设 \(num_i\) 为覆盖前 \(i\) 条线段且代价最小时最少的区间个数 ,那么因为 \(num_i\) 显然有单调性,所以我们每次转移时只需要选择最前面的一个决策点转移即可,即第一步操作弹出队首时,将条件 \(k_{a,b}\leq 2y_i\) 改为 \(k_{a,b}<2y_i\),这样就保证了相同优劣的决策点,前者不会被后者所弹出(第三步的条件不需要改,因为是前面的决策点弹出后面的决策点,不影响结果)

时间复杂度 \(\mathcal{O}(n\log V)\),其中 \(V\) 是二分范围,本题中为 \(m^2\)。浮点数比较建议使用 \(eps\)。代码倒是不难写。

#include <bits/stdc++.h>
using namespace std; #define ll long long
#define ld long double const int N=1e5+5;
const ld eps=1e-10; ll n,m,k,c,ans;
struct seg{
int l,r;
bool operator < (const seg &v) const{
return l!=v.l?l<v.l:r>v.r;
}
}p[N]; ll K,f[N],g[N],num[N];
ll sq(ll x){return x*x;}
ll Y(int i){return f[i]+sq(p[i+1].l)-g[i]-K;}
ll X(int i){return p[i+1].l;}
ld slope(int i,int j){return (ld)(Y(j)-Y(i))/(X(j)-X(i));} ll hd,tl,d[N];
bool check(){
d[hd=tl=1]=0;
for(int i=1;i<=n;i++){
while(hd<tl&&slope(d[hd],d[hd+1])+eps<=2*p[i].r)hd++;
int j=d[hd]; num[i]=num[j]+1,f[i]=f[j]+sq(p[i].r-p[j+1].l)-g[j]-K;
if(i<n)while(hd<tl&&slope(d[tl-1],d[tl])-eps>=slope(d[tl],i))tl--;
d[++tl]=i;
} return num[n]<=k;
} int main(){
cin>>n>>m>>k;
for(int i=1,c,r;i<=n;i++){
cin>>p[i].l>>p[i].r;
if(p[i].l>p[i].r)swap(p[i].l,p[i].r);
} sort(p+1,p+n+1);
for(int i=1,r=-1;i<=n;i++)if(p[i].r>r)r=p[i].r,p[++c]=p[i]; n=c;
for(int i=1;i<n;i++)if(p[i].r>=p[i+1].l)g[i]=sq(p[i].r-p[i+1].l+1);
for(int i=1;i<=n;i++)p[i].r++;
ll l=-1e12,r=0;
while(l<r)K=(l+r>>1)+1,check()?(l=K,ans=f[n]+K*k):r=K-1;
cout<<ans<<endl;
return 0;
}

P5896 [IOI2016]aliens的更多相关文章

  1. DP 优化方法大杂烩 & 做题记录 I.

    标 * 的是推荐阅读的部分 / 做的题目. 1. 动态 DP(DDP)算法简介 动态动态规划. 以 P4719 为例讲一讲 ddp: 1.1. 树剖解法 如果没有修改操作,那么可以设计出 DP 方案 ...

  2. Uva12206 Stammering Aliens 后缀数组&&Hash

    Dr. Ellie Arroway has established contact with an extraterrestrial civilization. However, all effort ...

  3. HDU4080 Stammering Aliens(二分 + 后缀数组)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...

  4. UVA 12206 - Stammering Aliens(后缀数组)

    UVA 12206 - Stammering Aliens 题目链接 题意:给定一个序列,求出出现次数大于m,长度最长的子串的最大下标 思路:后缀数组.搞出height数组后,利用二分去查找就可以 这 ...

  5. Stammering Aliens

    Stammering Aliens Time Limit: 2000MS   Memory Limit: 65536K       Description Dr. Ellie Arroway has ...

  6. XCOM2中敌对生物设计分析(Aliens篇)

    Aliens Aliens作为游戏设定中入侵的外星人,有各式外貌及奇特的战斗方式,掌握一些高能科技或利用精神力量进行攻击 Sectoid 使用灵能战斗的外星人,并无高级版本,初级便会使用精神控制,生命 ...

  7. UVA10570-Meeting with Aliens(枚举)

    Problem UVA1616-Caravan Robbers Accept: 531  Submit: 2490Time Limit: 3000 mSec Problem Description I ...

  8. 【UOJ#236】[IOI2016]railroad(欧拉回路,最小生成树)

    [UOJ#236][IOI2016]railroad(欧拉回路,最小生成树) 题面 UOJ 题解 把速度看成点,给定的路段看成边,那么现在就有了若干边,然后现在要补上若干边,以及一条\([inf,\) ...

  9. UVA-10570 Meeting with Aliens (枚举+贪心)

    题目大意:将一个1~n的环形排列变成升序的,最少需要几次操作?每次操作可以交换任意两个数字. 题目分析:枚举出1的位置.贪心策略:每次操作都保证至少一个数字交换到正确位置上. # include< ...

随机推荐

  1. vue3.x移动端适配px2rem

    1.什么是px2rem px2rem是一个插件能将px自动转换为rem,以适配各种不同的屏幕尺寸.前端开发可以直接使用设计稿量出的尺寸或者蓝湖给出的px进行布局,这样极大的提高了开发效率. 2.前提条 ...

  2. 第五课第四周实验一:Embedding_plus_Positional_encoding 嵌入向量加入位置编码

    目录 变压器预处理 包 1 - 位置编码 1.1 - 位置编码可视化 1.2 - 比较位置编码 1.2.1 - 相关性 1.2.2 - 欧几里得距离 2 - 语义嵌入 2.1 - 加载预训练嵌入 2. ...

  3. 洛谷 P5785 [SDOI2012] 任务安排

    链接: P5785 弱化版:P2365 题意: 有 \(n\) 个任务待完成,每个任务有一个完成时间 \(t_i\) 和费用系数 \(f_i\),相邻的任务可以被分成一批.从零时刻开始这些任务会被机器 ...

  4. Docker 安装 MySQL8

    1. 环境准备 创建挂载数据目录和配置文件 mkdir -p /mnt/mysql/data /etc/mysql/conf touch /etc/mysql/conf/my.cnf 2. 拉取镜像 ...

  5. POJ 3692 Kindergarten(二分图最大独立集)

    题意: 有G个女孩,B个男孩.女孩彼此互相认识,男孩也彼此互相认识.有M对男孩和女孩是认识的.分别是(g1,b1),.....(gm,bm). 现在老师要在这G+B个小孩中挑出一些人,条件是这些人都互 ...

  6. Windows内核基础知识-5-调用门(32-Bit Call Gate)

    Windows内核基础知识-5-调用门(32-Bit Call Gate) 调用门有一个关键的作用,就是用来提权.调用门其实就是一个段. 调用门: 这是段描述符的结构体,里面的s字段用来标记是代码段还 ...

  7. [WPF] 使用三种方式实现弧形进度条

    1. 需求 前天看到有人问弧形进度条怎么做,我模仿了一下,成果如下图所示: 当时我第一反应是可以用 Microsoft.Toolkit.Uwp.UI.Controls 里的 RadialGauge 实 ...

  8. 三(二)、AOP配置

    一.AOP的配置(注解) 步骤一.导入jar包: 处理那5个jar包之外,还需要导入: aopalliance aspectjweaver spring-aop spring-aspects 步骤二. ...

  9. C++ 入门到进阶 学习路线

    前言 学习这件事不在乎有没有人教你,最重要的是在于你自己有没有觉悟和恒心. -- 法布尔 简介 随着互联网及互联网+深入蓬勃的发展,经过40余年的时间洗礼,C/C++俨然已成为一门贵族语言,出色的性能 ...

  10. 'pybot' 不是内部或外部命令,也不是可运行的程序 或批处理文件

    在dos下运行pybot --version提示不是内部命令 这是pip list 打印信息: 解决方法: 在python/Scripts目录下加一个pybot.bat 文件 内容为: @Echo o ...