HDU - 3507 Print Article(斜率DP)
2015-10-07 10:14
288 查看
题目大意:就是那个公式了
解题思路: 以下参考了传送门
设dp[i]为前i个的和
则dp[i] = min(dp[j] + (sum[i] - sum[j]) ^ 2)
设j < k,则k点比j点更优,则
dp[j] + (sum[i] - sum[j]) ^ >= dp[k] + (sum[i] - sum[k]) ^ 2
化简得
dp[j] + sum[i] ^ 2 + sum[j] ^ 2 - 2 * sum[i] * sum[j] >= dp[k] + sum[i] ^ 2 + sum[k] ^ 2 -2 * sum[i] * sum[k]
即sum[i] >= (dp[k] + sum[k] ^ 2 - dp[j] - sum[j] ^ 2) / (sum[k] - sum[j])
现在假设yj = dp[j] - sum[j] ^ 2, xj = sum[j]
则上面不等式变为(yk - yj) / (xk - xj) <= sum[i]
随着i的增大,sum[i]是递增的
所以我们可以看出以下两点:我们令g[k,j]=(yk-yj)/(xk-xj)
第一:如果上面的不等式成立,那就说k比j优,而且随着i的增大上述不等式一定是成立的,也就是对i以后算DP值时,k都比j优。那么j就是可以淘汰的。
第二:如果 k < j < i 而且 g[k, j] > g[i, k] 那么 k 是可以淘汰的。
假设 g[i, k] < sum[i]就是i比k优,那么k没有存在的价值
相反如果 g[i, k] > sum[i] 那么同样有 g[k, j] > sum[i] 那么 j比 k优 那么 k 是可以淘汰的
所以这样相当于在维护一个下凸的图形,斜率在逐渐增大。
通过一个队列来维护。
解题思路: 以下参考了传送门
设dp[i]为前i个的和
则dp[i] = min(dp[j] + (sum[i] - sum[j]) ^ 2)
设j < k,则k点比j点更优,则
dp[j] + (sum[i] - sum[j]) ^ >= dp[k] + (sum[i] - sum[k]) ^ 2
化简得
dp[j] + sum[i] ^ 2 + sum[j] ^ 2 - 2 * sum[i] * sum[j] >= dp[k] + sum[i] ^ 2 + sum[k] ^ 2 -2 * sum[i] * sum[k]
即sum[i] >= (dp[k] + sum[k] ^ 2 - dp[j] - sum[j] ^ 2) / (sum[k] - sum[j])
现在假设yj = dp[j] - sum[j] ^ 2, xj = sum[j]
则上面不等式变为(yk - yj) / (xk - xj) <= sum[i]
随着i的增大,sum[i]是递增的
所以我们可以看出以下两点:我们令g[k,j]=(yk-yj)/(xk-xj)
第一:如果上面的不等式成立,那就说k比j优,而且随着i的增大上述不等式一定是成立的,也就是对i以后算DP值时,k都比j优。那么j就是可以淘汰的。
第二:如果 k < j < i 而且 g[k, j] > g[i, k] 那么 k 是可以淘汰的。
假设 g[i, k] < sum[i]就是i比k优,那么k没有存在的价值
相反如果 g[i, k] > sum[i] 那么同样有 g[k, j] > sum[i] 那么 j比 k优 那么 k 是可以淘汰的
所以这样相当于在维护一个下凸的图形,斜率在逐渐增大。
通过一个队列来维护。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 5000010; int dp , sum , que ; int n, m; void init() { sum[0] = dp[0] = 0; for (int i = 1; i <= n; i++) scanf("%d", &sum[i]); for (int i = 1; i <= n; i++) sum[i] += sum[i - 1]; } int getDP(int i, int j) { return dp[j] + (sum[i] - sum[j]) * (sum[i] - sum[j]) + m; } int getDown(int j, int k) { return 2 * (sum[j] - sum[k]); } int getUp(int j, int k) { return dp[j] + sum[j] * sum[j] - (dp[k] + sum[k] * sum[k]); } void solve() { int head , tail; head = tail = 0; que[tail++] = 0; for (int i = 1; i <= n; i++) { while (head + 1 < tail && getUp(que[head + 1], que[head]) <= sum[i] * getDown(que[head + 1], que[head])) head++; dp[i] = getDP(i, que[head]); while (head + 1 < tail && getUp(i, que[tail - 1]) * getDown(que[tail - 1], que[tail - 2]) <= getUp(que[tail - 1], que[tail - 2]) * getDown(i, que[tail - 1])) tail--; que[tail++] = i; } printf("%d\n", dp ); } int main() { while (scanf("%d%d", &n, &m) != EOF) { init(); solve(); } return 0; }
相关文章推荐
- UI_UITableViewController
- main cannot be resolved or is not a field
- 两个resourcemanager都处于standby,zkfc无法切换resourcemanager
- ERROR! MySQL manager or server PID file could not be found!
- Java学习之反射机制
- 关于nodejs使用sql时候出现的connect ECONNREFUSED
- iOS中日期和字符串的相互转化
- 机器学习与人工智能学习资源导引
- eclipse 优化 经常未响应解决办法
- libvirt API学习报告
- HelloWorld开启你的java之旅
- Map和HashMap
- 淘宝解禁百度抓取对SEO有何影响
- List接口和ArrayList类练习
- 天地图专题三:根据标注点的范围确定天地图的中心点和缩放级别
- print "hello" SyntaxError: Missing parentheses in call to 'print'
- 解决ECLIPSE 卡死的方法
- ubuntu安装libvirt
- 【Python】Learn Python the hard way, ex9 换行符,打印多行字符
- vs2015 打不开了 提示"CSharpPackage"