题意:需要打印n个正整数,1个数要么单独打印要么和前面一个数一起打印,1次打印1组数的代价为这组数的和的平方加上常数M。求最小代价。

思路:如果令dp[i]为打印前i个数的最小代价,那么有

dp[i]=min(dp[j]+(sum[i]-sum[j])2+M),j<i

直接枚举转移是O(n2)的,然而这个方程可以利用斜率优化将复杂度降到O(n)。

根据斜率优化的一般思路,对当前考虑的状态i,考虑决策j和k(j<k),如果k比j优,那么根据转移方程有:dp[k]+(sum[i]-sum[k])2+M ≤ dp[j]+(sum[i]-sum[j])2+M

整理可得:dp[k]+sum[k]2-2*sum[i]*sum[k] ≤ dp[j]+sum[j]2-2*sum[i]*sum[j]

然后进一步得到:[(dp[k]+sum[k]2)-(dp[j]+sum[j]2)] / (2*sum[k] - 2*sum[j]) ≤ sum[i]

如果令 y(i)=dp[i]+sum[i]2,x(i)=2*sum[i],那么有:( y(k)-y(j) ) / ( x(k)-x(j) ) ≤ sum[i],不妨令左边=G[j][k],即"j到k的斜率",G[j][k] ≤ sum[i]

注意,上面的推理的因果是等价的,也就是说 "k比j优" ↔ "( y(k)-y(j) ) / ( x(k)-x(j) ) ≤ sum[i]成立"

如果从小到大计算每个状态,那么(1)在某次计算状态i时,k比j优,由于sum数组单调递增,所以在以后的状态计算里面k都比j优(2)考虑三个状态i,j,k(i<j<k),满足G[i][j]≥G[j][k],那么在计算状态t(>k)的时候,{ 假设G[j][k]≤sum[t],k就比j优,否则G[j][k]>sum[t],那么显然有G[i][j]>sum[t],所以j不比i优 },所以对于t>k而言,j既没有k优也没有i优,完全可以舍弃。

在(2)的约束下,所有可能成为子状态的点构成了1个凸包,假设当前在计算状态i,这个凸包中最“前面”的两个点依次为j,k,如果G[j][k]≤sum[i],那么k比j优,把i从凸包里面删掉然后继续这样考虑,否则有G[j][k]>sum[i],说明j是最优的,因为对任意t∈(k,i)&&t∈凸包,都有G[j][t]>G[j][k]>sum[i],也就是没有比j更优的了。

虽然推理过程比较多,但是最后的结论非常的优美,程序也非常短,更重要的是,直接将原来O(n2)的复杂度降成了线性!没有比这更激动人心的了

#include <bits/stdc++.h>
using namespace std;
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;
#ifndef ONLINE_JUDGE
#include "local.h"
#endif
const int N = 5e5 + 7;
int head, tail;
pii q[N];
int n, m, x, sum[N]; int sqr(int x) { return x * x;}
int getY(int p) { return q[p].second + sqr(sum[q[p].first]); }
int getX(int p) { return 2 * sum[q[p].first]; }
int up(int p) { return getY(p + 1) - getY(p); }
int down(int p) { return getX(p + 1) - getX(p); }
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
while (cin >> n >> m) {
for (int i = 1; i <= n; i ++) {
scanf("%d", &x);
sum[i] = sum[i - 1] + x;
}
head = tail = 0;
q[tail ++] = mp(0, 0);
for (int i = 1; i <= n; i ++) {
while (tail - head > 1 && up(head) <= down(head) * sum[i]) head ++;
q[tail ++] = mp(i, q[head].second + sqr(sum[i] - sum[q[head].first]) + m);
while (tail - head > 2 && up(tail - 3) * down(tail - 2) >= up(tail - 2) * down(tail - 3)) {
swap(q[tail - 2], q[tail - 1]);
tail --;
}
}
cout << q[tail - 1].second << endl;
}
return 0;
}

  

[hdu3507 Print Article]斜率优化dp入门的更多相关文章

  1. hdu3507 Print Article[斜率优化dp入门题]

    Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  2. HDU3507 Print Article —— 斜率优化DP

    题目链接:https://vjudge.net/problem/HDU-3507 Print Article Time Limit: 9000/3000 MS (Java/Others)    Mem ...

  3. HDU3507 Print Article(斜率优化dp)

    前几天做多校,知道了这世界上存在dp的优化这样的说法,了解了四边形优化dp,所以今天顺带做一道典型的斜率优化,在百度打斜率优化dp,首先弹出来的就是下面这个网址:http://www.cnblogs. ...

  4. HDU3507 Print Article (斜率优化DP基础复习)

    pid=3507">传送门 大意:打印一篇文章,连续打印一堆字的花费是这一堆的和的平方加上一个常数M. 首先我们写出状态转移方程 :f[i]=f[j]+(sum[i]−sum[j])2 ...

  5. hdu 3507 Print Article(斜率优化DP)

    题目链接:hdu 3507 Print Article 题意: 每个字有一个值,现在让你分成k段打印,每段打印需要消耗的值用那个公式计算,现在让你求最小值 题解: 设dp[i]表示前i个字符需要消耗的 ...

  6. Print Article /// 斜率优化DP oj26302

    题目大意: 经典题 数学分析 G(a,b)<sum[i]时 a优于b G(a,b)<G(b,c)<sum[i]时 b必不为最优 #include <bits/stdc++.h& ...

  7. hdu 3507 Print Article —— 斜率优化DP

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3507 设 f[i],则 f[i] = f[j] + (s[i]-s[j])*(s[i]-s[j]) + m ...

  8. hdu3507(初识斜率优化DP)

    hdu3507 题意 给出 N 个数字,输出的时候可以选择连续的输出,每连续输出一串,它的费用是 这串数字和的平方加上一个常数 M. 分析 斜率优化dp,入门题. 参考 参考 得到 dp 方程后,发现 ...

  9. hdu3507Print Article(斜率优化dp)

    Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

随机推荐

  1. Teradata 数据库

    笔者大学所学计算机专业,读书时接触过Oracle.mysql和SQL SERVER,一度坐井观天觉得数据库应该也就这些了,但自笔者毕业进入数据仓库这个行业,接触的第一个商业数据库即是Teradata, ...

  2. CVE-2019-0193 Apache solr velocity模块漏洞

    Solr简单介绍 Solr是建立在Apache Lucene ™之上的一个流行.快速.开放源代码的企业搜索平台. Solr具有高度的可靠性,可伸缩性和容错能力,可提供分布式索引,复制和负载平衡查询,自 ...

  3. [整理]svn常见问题汇总

    1.’.’ is not a working copy.Can’t open file‘.svn/entries’: 系统找不到指定的路径.解答:原因是输入的访问路径不正确,如svn://192.16 ...

  4. Springboot:整合Mybaits和Druid【监控】(十一)

    MyBatis默认提供了一个数据库连接池PooledDataSource,在此我们使用阿里提供的Druid数据库连接池 项目下载:https://files.cnblogs.com/files/app ...

  5. leetcode-0543 二叉树的直径

    题目地址https://leetcode-cn.com/problems/diameter-of-binary-tree/ 递归+BFS(暴力解法) 我们可以考虑在每个节点时,都去计算该节点左子树和右 ...

  6. DEV gridview 合并单元格

    private void gv_docargo_CellMerge(object sender, DevExpress.XtraGrid.Views.Grid.CellMergeEventArgs e ...

  7. Python自然语言处理实战核心技术与算法,Python自然语言处理,PyTorch深度学习实战【下载】

    本人买的,无私贡献给大家,无解压密码 下载地址: 链接:https://pan.baidu.com/s/1cJtnhEQSXHVMgygr8PHh9A 提取码:a54u

  8. serialize和json_encode 区别

    (1)serialize主要用于php的序列化,存储到文件或者数据库中,json_encode 也是序列化,但是 主要用于与其他语言比如js进行交互使用,对于传输来说,json有许多优点. (2)在显 ...

  9. Linux安装jdk(详细教程)

    一.JDK介绍 JDK是 Java 语言的软件开发工具包,主要用于移动设备.嵌入式设备上的java应用程序.JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JA ...

  10. zabbix自动监控钉钉报警

    钉钉报警 一:设置钉钉机器人  二:zabbix服务器server端配置 1.修改zabbix_server.conf文件 [root@server ~]# vim /usr/local/zabbix ...