牛客多校第10场J Wood Processing 分治优化/斜率优化 DP
题意:你有n块木头,每块木头有一个高h和宽w,你可以把高度相同的木头合并成一块木头。你可以选择一些木头消去它们的一部分,浪费的部分是 消去部分的高度 * 木头的宽度,问把n块木头变成恰好m块木头至少要浪费多少木料?
思路:把木头从高到第排序,设dp[i][j]为前i块木头合并成了j块木头的最小花费。因为从大到小排序,所以合并后最后一块木头的高度一定是合并前的第i块木头的高度。那么,容易得出dp转移方程:dp[i][j] = min(dp[k][j - 1] + cal(k, i)),其中cal(k, i)为把第k + 1块木头到第i块木头的高度变成一样的花费。直接转移O(n * n * m),需要优化。
1:分治优化:设op[i][j]为向dp[i][j]转移的状态中最优值中最小的k,若op[i][j] <= op[i + 1][j], 那么便可以进行分治优化dp。对于此题,dp[x][j] + cal(x, i)和dp[y][j] + cal(y, j)(x < y)cal(x, i)和cal(y, i)有重合部分,所以有op[i][j] <= op[i + 1][j], 通过分治的过程可以缩小转移的范围,复杂度O(n * logn * m)。
代码:
#include <bits/stdc++.h>
#define LL long long
#define pll pair<LL, LL>
#define INF 1e18
using namespace std;
const int maxn = 5010;
const int maxm = 2010;
pll a[maxn];
int n, m;
LL f[maxm][maxn], w[maxn], sum[maxn];
LL cal(LL l, LL r, LL h) {
return sum[r] - sum[l] - h * (w[r] - w[l]);
}
void solve(int x, int l, int r, int opl, int opr) {
if(l > r) return;
int mid = (l + r) >> 1;
pll ans = make_pair(INF, INF);
for (int i = opl; i < mid && i <= opr; i++) {
ans = min(ans, make_pair(f[x - 1][i] + cal(i, mid, a[mid].first), (LL)i));
}
f[x][mid] = ans.first;
LL opt = ans.second;
solve(x, l, mid - 1, opl, opt);
solve(x, mid + 1, r, opt, opr);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &a[i].second, &a[i].first);
}
sort(a + 1, a + 1 + n);
reverse(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++) {
w[i] = w[i - 1] + a[i].second;
sum[i] = sum[i - 1] + a[i].second * a[i].first;
}
for (int i = 1; i <= n; i++)
f[1][i] = cal(0, i, a[i].first);
for (int i = 2; i <= m; i++) {
solve(i, 1, n, 0, n);
}
printf("%lld\n", f[m][n]);
}
思路2:斜率优化,把cal(k, i)式子列出来,用单调队列维护下凸包。场上没注意到斜率乘积会爆long long,非常可惜QAQ
#include <bits/stdc++.h>
#define LL long long
#define pll pair<LL, LL>
using namespace std;
const int maxn = 5010;
const int maxm = 2010;
pll a[maxn];
int n, m;
LL f[maxn][maxn], w[maxn], sum[maxn];
int q[maxn][maxm], l[maxm], r[maxm];
LL cal(LL x, LL y) {
return f[x][y] - sum[x];
}
void update(int x, int y) {
LL h = -a[x].first;
while(l[y] < r[y]) {
int p1 = q[y][l[y]], p2 = q[y][l[y] + 1];
__int128 t = (__int128)cal(p2, y) - cal(p1, y);
__int128 t1 = (__int128)h * (w[p2] - w[p1]);
if(t <= t1) {
l[y]++;
continue;
} else {
break;
}
}
int k = q[y][l[y]];
f[x][y + 1] = f[k][y] + sum[x] - sum[k] + h * (w[x] - w[k]);
while(l[y] < r[y]) {
int p1 = q[y][r[y] - 1], p2 = q[y][r[y]];
__int128 t = (__int128)(cal(p2, y) - cal(p1, y)) * (w[x] - w[p2]);
__int128 t1 = (__int128)(cal(x, y) - cal(p2, y)) * (w[p2] - w[p1]);
if(t >= t1) {
r[y]--;
continue;
} else {
break;
}
}
q[y][++r[y]] = x;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d%d", &a[i].second, &a[i].first);
}
sort(a + 1, a + 1 + n);
reverse(a + 1, a + 1 + n);
for (int i = 1; i <= m; i++) {
l[i] = 1, r[i] = 1;
q[i][1] = 0;
}
for (int i = 1; i <= n; i++) {
w[i] = w[i - 1] + a[i].second;
sum[i] = sum[i - 1] + a[i].second * a[i].first;
}
for (int i = 1; i <= n; i++) {
f[i][1] = sum[i] - a[i].first * w[i];
for (int j = 2; j <= m; j++) {
update(i, j - 1);
}
}
printf("%lld\n", f[n][m]);
}
牛客多校第10场J Wood Processing 分治优化/斜率优化 DP的更多相关文章
- 牛客多校第四场 J.Hash Function(线段树优化建图+拓扑排序)
题目传送门:https://www.nowcoder.com/acm/contest/142/J 题意:给一个hash table,求出字典序最小的插入序列,或者判断不合法. 分析: eg.对于序列{ ...
- 牛客多校第3场 J 思维+树状数组+二分
牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...
- 牛客多校第五场 J:Plan
链接:https://www.nowcoder.com/acm/contest/143/J 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524 ...
- 牛客多校第六场 J Heritage of skywalkert 随即互质概率 nth_element(求最大多少项模板)
链接:https://www.nowcoder.com/acm/contest/144/J来源:牛客网 skywalkert, the new legend of Beihang University ...
- 2019 牛客多校第六场 J Upgrading Technology
题目链接:https://ac.nowcoder.com/acm/contest/886/J 题目大意 略. 分析 见代码. 代码如下 #include <bits/stdc++.h> u ...
- 牛客多校训练营第九场 J - Symmetrical Painting (排序)
J - Symmetrical Painting 题意 给你\(n\)个矩形, 左下角\((i-1,\ L_i)\), 右上角\((i,\ R_i)\), 找一条线\(l\)平行于\(x\)轴, 让这 ...
- 18牛客多校训练第二场 J farm
题意:一个n×m的农田, 每个小格子都有一种作物, 现在喷t次农药,每次农药覆盖一个矩形, 该矩形里面与农药类型不同的植物都会死掉, 求最后植物的死亡数是多少. 题解:二维树状数组. 每次喷农药的时候 ...
- 2019牛客多校第四场J free——分层图&&最短路
题意 一张无向图,每条边有权值,可以选择不超过 $k$ 条路使其权值变成0,求 $S$ 到 $T$ 的最短路.(同洛谷 P4568) 分析 首先,分层图最短路可以有效解决这种带有 「阶段性」的最短路, ...
- 牛客多校第六场 J Upgrading Technology dp
题意: 有n个技能,一开始都是0级,第i个技能从j-1级升到j级,花费$c_{i,j}$,但是花费不一定是正的 所有的技能升到j级时,奖励$d_j$但是奖励也不一定是正的 题解: 用sum[i][j] ...
随机推荐
- [洛谷P1514] NOIP2010 引水入城
问题描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行×M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度. ...
- ubuntu + JetSonNano+OpenCV3.4.8
首先强调一点,如果要配置darknet环境,不建议安装该版本!!! 安装opencv前,建议先检测自己的系统是否已经装过其他版本, 检查方式: (1)查看是否安装opencv库: pkg-config ...
- Mac Pro 安装win10记录(不用优盘版)
用启动转换助理 就可以了提前下好win10 iso系统镜像文件,然后Mac会自动安装.然后一直下一步就可以了. 我这次装好之后无法连接网络,发现是因为win网卡驱动没有,所以回到Mac系统下 把需要的 ...
- EditText控件常用属性
常用属性 android:id——控件ID android:layout_width——控件宽度 android:layout_height——控件高度 android:text——文本内容 andr ...
- win7下redis开机自启动设置
win7下安装完redis之后,每次开机都得用cmd命令行启动redis,所以就想办法实现开机自启动redis. 一.把启动命令写入bat: E:\redis\redis-server.exe E:\ ...
- Spring Security 3.1 中功能强大的加密工具 PasswordEncoder
Spring Security 3.1 中功能强大的加密工具 PasswordEncoder 博客分类: security spring springsecurity 好吧,这种加密机制很复杂,还是 ...
- 学习日记13、ajax同时提交from表单和多个参数
if ($("form").valid()) { $.ajax({ url: "@Url.Action("EditCusAndCusCard")&qu ...
- leetcode 230. 二叉搜索树中第K小的元素(C++)
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: root = [ ...
- RESTful再理解
目录 目录 前言 RESTful的目的 REST的含义 表现层 状态转化 无状态协议HTTP 最后 前言 这是在经过一段时间的积累后,对RESTFul框架的再一次更深入的理解.希望能够将零散的知识点连 ...
- CentOS 7.3 安装MySQL 5.7并修改初始密码
在CentOS 7.3 下安装MySQL 5.7并修改初始密码,Windows下安装MySQL 5.7 见 http://www.linuxidc.com/Linux/2017-11/148521.h ...