BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】
题目链接
洛谷P1912【原题,需输出方案】
BZOJ1563【无SPJ,只需输出结果】
题解
四边形不等式
什么是四边形不等式?
一个定义域在整数上的函数\(val(i,j)\),满足对\(\forall a \le b \le c \le d\)有
\]
那么我们称函数\(val(i,j)\)满足四边形不等式
一般地,当我们需要证明一个函数\(val(i,j)\)满足四边形不等式时,只需证对于\(\forall j < i\)有
\]
因为若该条件满足,
那么有
对于\(j < i\)有
\]
对于\(j + 1 < i\)有
\]
两式相加
\]
同理,只要满足第一个条件,对于\(\forall j + x < i + y\)都能推出
\]
所以对\(\forall a \le b \le c \le d\)有
\]
证毕
如何使用四边形不等式优化\(dp\)?
如果我们有这样一个递推式
\]
如果是\(1D1D\)方程,自然可以单调队列或者斜率优化
但是如果\(val(i,j)\)比较复杂,无法展开,我们不能有效地分离\(i,j\)变量,斜率优化就失效了
这个时候就要考虑\(val(j,i)\)是否满足四边形不等式
假使\(val(j,i)\)是满足的
那么我们对\(f[i]\)求出了一个最优转移位置,即为\(p[i]\)
那么对于\(\forall j < p[i]\),都有
\]
我们现在要求\(f[k]\),其中\(k > i\)
以上我们有\(j < p[i] < i < k\)
那么由四边形不等式:
\]
交换一下
\]
与\(f[p[i]] + val(p[i],i) \le f[j] + val(j,i)\)相加
得
\]
得证\(f[k]\)的决策\(p[k] \ge p[i]\)
换言之,\(f[i]\)的决策满足决策单调性
对于\(\forall i > j\)都有\(p[i] \ge p[j]\)
我们就可以从这里入手优化这个\(O(n^2)\)的转移
为求出\(f[i]\),我们只需求出\(p[i]\)数组
一开始令\(p[i] = 0\),即未开始转移前所有位置的最优决策为位置\(0\)
之后从小枚举\(i\)
枚举到\(i\)时,\(i\)处最优决策更新完毕,那么\(\forall j \le i\),\(p[j]\)和\(f[j]\)都已经计算
为了更新\(p[i]\)数组,我们只需找到\(i\)所能更新的最左的位置\(l\),由于决策的单调性,\([l,n]\)的决策都将更新为\(i\)
此时二分判断即可
由于需要进行区间赋值,我们可以用一个队列来优化以上操作
具体地,储存若干三元组\((pos,l,r)\),表示区间\([l,r]\)的决策为\(pos\),每次更新从队尾逐个取出检查即可
复杂度优化为\(O(nlogn)\)
诗人小G
设\(f[i]\)为前\(i\)个句子排版的最小不和谐度
记\(len[i]\)为句子\(i\)的长度,\(sum[i]\)为句子长度前缀和
容易写出转移方程
\]
我们记\(val(j,i) = |(sum[i] - sum[j]) + (i - j - 1) - L|^{P}\),显然无法进行斜率优化
考虑\(val(j,i)\)是否满足四边形不等式,即\(f[i]\)的决策是否具有单调性
我们可以打表证明
要证\(val(j,i)\)满足四边形不等式,只需证对\(\forall j < i\)
\]
即证
\]
观察\(val(j,i) = |(sum[i] + i) - (sum[j] + j) - (L + 1)|^{P}\)
我们令\(x = (sum[i] + i) - (sum[j] + j) - (L + 1)\)
我们令\(y = (sum[i] + i) - (sum[j + 1] + j + 1) - (L + 1)\)
那么原式化为:
\]
又因为\(x > y\)
我们只需证对于函数\(f(x) = |x|^{P} - |x + c|^{P}\)关于\(x\)单调递减,其中\(c\)为大于\(0\)的常数
可以使用导数分类讨论得证
于是就可以用四边形不等式优化成\(O(nlogn)\)
不输出方案版:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long double
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
inline void write(LL x){
if (x / 10 >= 1) write(x / 10);
putchar((int)floor(x - floor(x / 10) * 10) + '0');
}
int n,P,L;
LL f[maxn],a[maxn],sum[maxn];
char s[maxn][32];
int head,tail;
struct node{
int j,l,r;
}q[maxn * 3];
LL qpow(LL a,int b){
LL re = 1;
for (; b; b >>= 1,a = a * a)
if (b & 1) re = re * a;
return re;
}
LL val(int i,int j){
return qpow(fabs(sum[i] - sum[j] + (i - j - 1) - L),P);
}
bool check(int a,int b,int i){
return f[a] + val(i,a) <= f[b] + val(i,b);
}
int main(){
int T = read();
while (T--){
n = read(); L = read(); P = read();
sum[0] = f[0] = 0;
REP(i,n){
scanf("%s",s[i] + 1),a[i] = strlen(s[i] + 1);
sum[i] = sum[i - 1] + a[i];
f[i] = val(i,0);
}
q[head = tail = 0] = (node){0,1,n};
node u; int l,r,mid;
for (int i = 1; i <= n; i++){
f[i] = f[q[head].j] + val(i,q[head].j);
q[head].l++;
if (q[head].l > q[head].r) head++;
while (head <= tail){
u = q[tail--];
if (check(i,u.j,u.l)){
if (head > tail){
q[++tail] = (node){i,i + 1,n};
break;
}
}
else if (!check(i,u.j,u.r)){
q[++tail] = u;
if (u.r == n) break;
else{
q[++tail] = (node){i,u.r + 1,n};
break;
}
}
else {
l = u.l; r = u.r;
while (l < r){
mid = l + r >> 1;
if (check(i,u.j,mid)) r = mid;
else l = mid + 1;
}
q[++tail] = (node){u.j,u.l,l - 1};
q[++tail] = (node){i,l,n};
break;
}
}
}
if (f[n] > qpow(10,18)) puts("Too hard to arrange");
else write(f[n]),puts("");
printf("--------------------");
if (T) puts("");
}
return 0;
}
输出方案版
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long double
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
inline void write(LL x){
if (x / 10 >= 1) write(x / 10);
putchar((int)floor(x - floor(x / 10) * 10) + '0');
}
int n,P,L,p[maxn];
LL f[maxn],a[maxn],sum[maxn];
char s[maxn][32];
int head,tail;
struct node{
int j,l,r;
}q[maxn * 3];
LL qpow(LL a,int b){
LL re = 1;
for (; b; b >>= 1,a = a * a)
if (b & 1) re = re * a;
return re;
}
LL val(int i,int j){
return qpow(fabs(sum[i] - sum[j] + (i - j - 1) - L),P);
}
bool check(int a,int b,int i){
return f[a] + val(i,a) <= f[b] + val(i,b);
}
void print(int u){
if (p[u]) print(p[u]);
for (int i = p[u] + 1; i <= u; i++){
printf("%s",s[i] + 1);
putchar(i < u ? ' ' : '\n');
}
}
int main(){
int T = read();
while (T--){
n = read(); L = read(); P = read();
sum[0] = f[0] = 0;
REP(i,n){
scanf("%s",s[i] + 1),a[i] = strlen(s[i] + 1);
sum[i] = sum[i - 1] + a[i];
f[i] = val(i,0);
}
q[head = tail = 0] = (node){0,1,n};
node u; int l,r,mid;
for (int i = 1; i <= n; i++){
f[i] = f[q[head].j] + val(i,q[head].j);
p[i] = q[head].j;
q[head].l++;
if (q[head].l > q[head].r) head++;
while (head <= tail){
u = q[tail--];
if (check(i,u.j,u.l)){
if (head > tail){
q[++tail] = (node){i,i + 1,n};
break;
}
}
else if (!check(i,u.j,u.r)){
q[++tail] = u;
if (u.r == n) break;
else{
q[++tail] = (node){i,u.r + 1,n};
break;
}
}
else {
l = u.l; r = u.r;
while (l < r){
mid = l + r >> 1;
if (check(i,u.j,mid)) r = mid;
else l = mid + 1;
}
q[++tail] = (node){u.j,u.l,l - 1};
q[++tail] = (node){i,l,n};
break;
}
}
}
if (f[n] > qpow(10,18)) puts("Too hard to arrange");
else{
write(f[n]),puts("");
print(n);
}
printf("--------------------");
if (T) puts("");
}
return 0;
}
BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】的更多相关文章
- [BZOJ1563][NOI2009]诗人小G(决策单调性优化DP)
模板题. 每个决策点都有一个作用区间,后来的决策点可能会比先前的优.于是对于每个决策点二分到它会比谁在什么时候更优,得到新的决策点集合与区间. #include<cstdio> #incl ...
- [NOI2009]诗人小G 决策单调性优化DP
第一次写这种二分来优化决策单调性的问题.... 调了好久,,,各种细节问题 显然有DP方程: $f[i]=min(f[j] + qpow(abs(sum[i] - sum[j] - L - 1))); ...
- 洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP
洛谷 P4093 [HEOI2016/TJOI2016]序列 CDQ分治优化DP 题目描述 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他. 玩具上有一个数列,数列中某些项的值可能会 ...
- CF321E Ciel and Gondolas Wqs二分 四边形不等式优化dp 决策单调性
LINK:CF321E Ciel and Gondolas 很少遇到这么有意思的题目了.虽然很套路.. 容易想到dp \(f_{i,j}\)表示前i段分了j段的最小值 转移需要维护一个\(cost(i ...
- hdu 2829 Lawrence(四边形不等式优化dp)
T. E. Lawrence was a controversial figure during World War I. He was a British officer who served in ...
- 【转】斜率优化DP和四边形不等式优化DP整理
(自己的理解:首先考虑单调队列,不行时考虑斜率,再不行就考虑不等式什么的东西) 当dp的状态转移方程dp[i]的状态i需要从前面(0~i-1)个状态找出最优子决策做转移时 我们常常需要双重循环 (一重 ...
- codevs3002石子归并3(四边形不等式优化dp)
3002 石子归并 3 参考 http://it.dgzx.net/drkt/oszt/zltk/yxlw/dongtai3.htm 时间限制: 1 s 空间限制: 256000 KB 题目等级 ...
- 洛谷 P3580 - [POI2014]ZAL-Freight(单调队列优化 dp)
洛谷题面传送门 考虑一个平凡的 DP:我们设 \(dp_i\) 表示前 \(i\) 辆车一来一回所需的最小时间. 注意到我们每次肯定会让某一段连续的火车一趟过去又一趟回来,故转移可以枚举上一段结束位置 ...
- 学习笔记:四边形不等式优化 DP
定义 & 等价形式 四边形不等式是定义在整数集上的二元函数 \(w(x, y)\). 定义:对于任意 \(a \le b \le c \le d\),满足交叉小于等于包含(即 \(w(a, c ...
随机推荐
- 【linux】vim常用快捷键(转)
原文链接:https://www.cnblogs.com/tianyajuanke/archive/2012/04/25/2470002.html 1.vim ~/.vimrc 进入配置文件 如果不知 ...
- 性能测试工具——LoadRunner篇(一)
一.LoadRunner组件 1.Virtual User Generato——r录制最终用户业务流程并创建性能 2.Controller——组织.驱动.管理并发监控负载测试 3.Analysis—— ...
- 使用Idea工具创建Maven WebApp项目
(1)New Project,选择模板,配置SDK (2)配置项目名及项目组名 GroupID是项目组织唯一的标识符, 比如我的项目叫test001 那么GroupID应该是 com.lixiaomi ...
- PostgreSQL9.6主从配置
参考文档: 备机日志传送:https://www.postgresql.org/docs/9.6/static/warm-standby.html 英文文档:https://www.postgresq ...
- 从无到有之webpack+vuerouter的简单例子以及各个属性解释
之前一直没玩过webpack和vue,近两周才看这玩意,本文纯属自己的实验+之前angular作战经验的理解一些入门文章 首先webpack关于vue以及各个包 module.exports = { ...
- pspo过程文档
项目计划总结: 日期/任务 听课 编写程序 阅读相关书籍 日总计 周一 110 60 ...
- web项目页面加载时,下拉框有值
1.我用的框架是springmvc和mybaitis 由于没有整个项目,直接就去请求的action :http://localhost:8080/ytert/test/selectStoreType ...
- Nginx 配置站点
1-进入 配置文件夹 cd /etc/nginx/cof.d 2-创建一个一站点名称命名的配置文件 vim kestrel-syslyracom.conf 3-在.conf 文件中输入 ...
- Dijkstra、Bellman_Ford、SPFA、Floyd算法复杂度比较
参考 有空再更新下用c++, 下面用的Java Dijkstra:适用于权值为非负的图的单源最短路径,用斐波那契堆的复杂度O(E+VlgV) BellmanFord:适用于权值有负值的图的单源最短路径 ...
- 第一阶段android学习笔记
1.学习<第一行代码> 第一个android项目: 项目的注意点,如创建项目时包名具有唯一性,在做项目的时候要手动改成Project模式.还知道了引用字符串的两种方式. AS项目的三种依赖 ...