参考资料:

李煜东《算法竞赛进阶指南》

斜率优化

形如:

\(f[i] = min\{f[j]+val(i,j)\}\)的dp,多项式\(val(i,j)\)包含\(i,j\)的乘积项

引入一个例题:

[HNOI2008]玩具装箱TOY

\(dp[i] = min\{dp[j] + (sum[i] + i - sum[j] - j-L-1)^2\}(j < i)\)

定义:\(a[i]=sum[i]+i,b[i]=sum[i]+i+L+1\)

\[dp[i]=dp[j]+(a[i]-b[j])^2\\
dp[i]=dp[j]+a[i]^2-2*a[i]*b[j]+b[j]^2\\
2*a[i]*b[j]+dp[i]-a[i]^2=dp[j]+b[j]^2\\
\]

将\(b[j]\)看作x,\(dp[j]+b[j]^2\)看作y

那么这个式子就是一个\(k=2*a[i]\)的直线

那么我们要最小化这个过\((b[j],dp[j]+b[j]^2)\)的直线的\(b\)值

根据定义,\(a[i]\)单调递增,那么直线的斜率越来越大

我们可以用单调队列维护下凸壳,不断用\(a[i]\)去切这个凸包

习题:

[APIO2014]序列分割

[APIO2010]特别行动队

[CEOI2004]锯木厂选址

wqs二分/带权二分/凸优化

解决n个东西恰好选m个的最优问题

普通dp方法一般都是\(O(nm)\)

wqs二分可以优化成\(O(nlogW)\)

引入例题:

有n个物品,每个物品有一个价值,

问:选m个物品可以获得的最大价值。

这显然可以贪心,但是我们为了引出wqs二分,我们想dp做法

\(f[i][j]=max(f[i-1][j-1]+val[i],f[i-1][j])\)

考虑如果没有m的限制,那么dp式子长这样

\(f[i]=f[i-1]+max(v[i],0)\)

wqs二分又称带权二分

那么我们二分这个带权x

给每个物品价值增加x

显然x越大,我们会选的东西不会变少

如果选的个数大于m,那么x要减小,否则增大

最后\(ans=f[n]-x*m\)

整数二分x可能会有些精度问题,最好是写实数二分

习题:

[八省联考2018]林克卡特树lct

四边形不等式优化

这个东西比较难,看不懂的可以记住结论。(证明由于篇幅过长,有兴趣的可以去查找一下资料)

​ 设\(w(x,y)\)是定义在整数集合的二元函数。若对于定义域上的任意整数\(a,b,c,d\),其中\(a\leq b \leq c \leq d\),都有\(w(a,d)+w(b,c)≥w(a,c)+w(b,d)\)成立,则称函数\(w\)满足四边形不等式。

定理(四边形不等式的另一种定义):对于定义域上任意整数\(a,b\),其中\(a<b\),都有\(w(a,b+1)+w(a+1,b)≥w(a,b)+w(a+1,b+1)\)成立,则函数满足四边形不等式。

一维线性dp的四边形不等式优化

​ 形如:\(f[i]=min\{f[j]+val(j,i)\}\)的dp,记\(p[i]\)为令\(f[i]\)取到最小值的j的值,即\(p[i]\)是\(f[i]\)的最优决策。若\(p\)在\([1,N]\)上单调不减,则称\(f\)具有决策单调性

定理(决策单调性):在上述dp中,若\(val\)满足四边形不等式,则\(f\)满足决策单调性。

那么,当\(F\)有决策单调性时,我们可以把复杂度降低到\(O(nlogn)\)

考虑维护\(p\)数组。最初\(p\)数组全部为0。在\(i\)循环进行的任意时刻,根据\(p[i]\)的单调性,情况应该如下图所示:

\(p:[j1,j1,j2,j3,j3,j3,j4,j4,j5,j5,j5]\) \((j1<j2<j3<j4<j5)\)

当求出一个新的\(f[i]\)时,我们应该考虑\(i\)可以作为哪些\(F[i'](i'>i)\)的最优决策。根据决策单调性,最终我们会找到一个位置,在该位置之前,p数组原来的决策比i好,之后的比i差。这个位置可以二分求得。

怎么修改?

直接修改数组效率肯定不行,我们可以建立一个队列保存三元组\((j,l,r)\),\(j\)表示决策,\(l,r\)表示 \(p[ l-r ]\) 值都为 \(j\)

然后像单调队列一样维护即可。

例题:诗人小G

按照上面的模拟即可,注意用long double(精度高) 代替long long。

#include<bits/stdc++.h>

#define LL long long
#define RG register using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
#define ld long double
const int N = 100010;
int n, L, P;
ld sum[N], f[N];
char str[N][35];
ld fpow(ld a, int b) {
ld res = 1;
for (; b; b >>= 1, a = a * a) if (b & 1) res = res * a;
return res;
}
ld getans(int l, int r) {
return f[l] + fpow(abs(sum[r] - sum[l] + (r - l - 1) - L), P);
}
struct node {
int j, l, r;
} q[N];
int find(int l, int r, int j, int i) {
int ans = -1;
while (l <= r) {
int mid = (l + r) >> 1;
getans(j, mid) >= getans(i, mid) ? ans = mid, r = mid - 1 : l = mid + 1;
}
return ans;
}
int p[N], que[N];
void solve() {
read(n), read(L), read(P);
for (int i = 1; i <= n; i++) {
scanf("%s", str[i]);
sum[i] = sum[i - 1] + (int) strlen(str[i]);
}
int l = 0, r = 0;
q[l] = (node) {0, 1, n};
for (int i = 1; i <= n; i++) {
if (q[l].r < i) l++;
p[i] = q[l].j; q[l].l = i;
f[i] = getans(q[l].j, i);
while (l <= r && getans(q[r].j, q[r].l) >= getans(i, q[r].l)) r--;
if (getans(q[r].j, q[r].r) < getans(i, q[r].r)) { if (q[r].r < n) q[r + 1] = (node) {i, q[r].r + 1, n}, r++; }
else {
int pos = find(q[r].l, q[r].r, q[r].j, i);
q[r].r = pos - 1;
q[++r] = (node) {i, pos, n};
}
}
if (f[n] > 1e18) puts("Too hard to arrange");
else {
printf("%lld\n", (LL) f[n]);
int now = n, tot = 0;
while (now) que[++tot] = now, now = p[now];
que[tot + 1] = 0;
for (int i = tot; i; i--) {
for (int j = que[i + 1] + 1; j < que[i]; j++)
printf("%s ", str[j]);
puts(str[que[i]]);
} }
puts("--------------------");
return ;
}
int main() {
int T;
read(T);
while (T--) solve();
return 0;
}

二维区间DP的四边形不等式优化

区间DP问题

一类区间问题的转移方程:

\(f[i][j]=min\{f[i][k]+f[k+1][j]+w(i,j)\}\)

定理

​ 在上述方程中,如果\(w\)满足四边形不等式,且\(w(a,d)≥w(b,c)[a≤b≤c≤d]\)

那么\(f\)也满足四边形不等式

二维决策单调性

​ 记\(p[i][j]\)为令\(f[i][j]\)取到最小值的\(k\)值,如果\(f\)满足四边形不等式,那么对于任意\(i<j\),有\(p[i][j-1]≤p[i][j]≤p[i+1][j]\)

例题:[IOI2000]邮局

先写出转移方程:\(f[i][j]=min\{f[i][j],f[k][j−1]+dis(k+1,i)\}\)

显然这个\(dis\)满足四边形不等式。

那么这个\(f\)满足决策点单调性

#include<bits/stdc++.h>

#define LL long long
#define RG register using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 3010;
int a[N], n, m, p[N][N], sum[N], f[N][N], w[N][N]; int main() {
read(n), read(m);
for (int i = 1; i <= n; i++) read(a[i]);
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++) {
int mid = (i + j) >> 1;
w[i][j] = a[mid] * (mid - i) - (sum[mid - 1] - sum[i - 1]);
w[i][j] += (sum[j] - sum[mid]) - a[mid] * (j - mid);
}
memset(f, 63, sizeof(f));
for (int i = 1; i <= n; i++)
f[i][1] = w[1][i];
for (int j = 2; j <= m; j++) {
p[n + 1][j] = n;
for (int i = n; i >= 1; i--)
for (int k = p[i][j - 1]; k <= p[i + 1][j]; k++)
if (f[i][j] > f[k][j - 1] + w[k + 1][i]) {
f[i][j] = f[k][j - 1] + w[k + 1][i];
p[i][j] = k;
}
}
printf("%lld\n", f[n][m]);
return 0;
}

DP的优化的更多相关文章

  1. 【BZOJ-4518】征途 DP + 斜率优化

    4518: [Sdoi2016]征途 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 230  Solved: 156[Submit][Status][ ...

  2. 【BZOJ-3437】小P的牧场 DP + 斜率优化

    3437: 小P的牧场 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 705  Solved: 404[Submit][Status][Discuss ...

  3. 【BZOJ-1010】玩具装箱toy DP + 斜率优化

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 8432  Solved: 3338[Submit][St ...

  4. 【Codeforces 321E / BZOJ 5311】【DP凸优化】【单调队列】贞鱼

    目录 题意: 输入格式 输出格式 思路: DP凸优化的部分 单调队列转移的部分 坑点 代码 题意: 有n条超级大佬贞鱼站成一行,现在你需要使用恰好k辆车把它们全都运走.要求每辆车上的贞鱼在序列中都是连 ...

  5. HDU3480_区间DP平行四边形优化

    HDU3480_区间DP平行四边形优化 做到现在能一眼看出来是区间DP的问题了 也能够知道dp[i][j]表示前  i  个节点被分为  j  个区间所取得的最优值的情况 cost[i][j]表示从i ...

  6. 动态规划DP的优化

    写一写要讲什么免得忘记了.DP的优化. 大概围绕着"是什么","有什么用","怎么用"三个方面讲. 主要是<算法竞赛入门经典>里 ...

  7. 【bzoj5197】[CERC2017]Gambling Guide 期望dp+堆优化Dijkstra

    题目描述 给定一张n个点,m条双向边的无向图. 你要从1号点走到n号点.当你位于x点时,你需要花1元钱,等概率随机地买到与x相邻的一个点的票,只有通过票才能走到其它点. 每当完成一次交易时,你可以选择 ...

  8. 「学习笔记」wqs二分/dp凸优化

    [学习笔记]wqs二分/DP凸优化 从一个经典问题谈起: 有一个长度为 \(n\) 的序列 \(a\),要求找出恰好 \(k\) 个不相交的连续子序列,使得这 \(k\) 个序列的和最大 \(1 \l ...

  9. 【BZOJ】1096: [ZJOI2007]仓库建设(dp+斜率优化)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1096 首先得到dp方程(我竟然自己都每推出了QAQ)$$d[i]=min\{d[j]+cost(j+ ...

  10. BZOJ 1096: [ZJOI2007]仓库建设(DP+斜率优化)

    [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L公司一般把产品直接堆放在 ...

随机推荐

  1. Go学习路径--相关基础

    现在开始接触Go一段时间了,基本路径就是看基础学习材料,开始写项目,有问题找解决问题的方法.这里记录一下学习过程. go相关文章 Golang适合高并发场景的原因分析 go build 不同系统下的可 ...

  2. 在Angular中使用$ compile

    转载自:http://odetocode.com/blogs/scott/archive/2014/05/07/using-compile-in-angular.aspx 在AngularJS中创建一 ...

  3. Scientific Toolworks Understand for linux

    Scientific Toolworks Understand for linux 这个软件我找了很久了,一直没有找到合适能装的.现在这款能在linux上顺利运行的版本,共享给需要的TX们. 个人觉得 ...

  4. 字蛛webfont 安装及使用方法

    先安装nodejs和git,比如放在D:/nodejs/  文件夹 cmd 进入该文件夹,安装npm install express 安装 npm install font-spider -g 安装  ...

  5. sql 给相同属性的数据排序

    UPDATE b SET OrderIndex = a.OrderIndex FROM ( SELECT RTRIM(ROW_NUMBER() OVER ( PARTITION BY [ItemID] ...

  6. main函数前后

    void f1(void)__attribute__((constructor)); void f2(void)__attribute__((destructor)); void f1(void) { ...

  7. 简单实现app使用PC图片

    提一个很人性化的需求: 在自己的app里使用PC里的图片. 关键点:传输.怎么把图片从PC导入自己的APP. 因为iOS的封闭性,一般用户不能很方便把图片导入手机相册.笔者稍微想了下,实现功能其实也有 ...

  8. pytorch之nn.Conv1d详解

    转自:https://blog.csdn.net/sunny_xsc1994/article/details/82969867,感谢分享 pytorch之nn.Conv1d详解

  9. 取出List<Map<String,Object>>里面Map的key:value值

    1.取出Map其中一个属性的值 Map map = new HashMap(); map.put("key1", "value1"); map.put(&quo ...

  10. 一组简单好看的css3渐变按钮

    主要代码如下: body { background:#fff } /* Mixins */ /* bg shortcodes */ .bg-gradient1 span,.bg-gradient1:b ...