hdu 3507 Print Article
http://acm.hdu.edu.cn/showproblem.php?pid=3507
从http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html这个博客里找的题,讲的很详细,推荐之~~~
dp[i] = MIN(dp[j] + (ans[i]- ans[j])*^2) + m;
若j为最优解,则 dp[j] + (ans[i] - ans[j])^2 + m < dp[k] + (ans[i] - ans[k])^2 + m;
化简:
dp[j] + ans[i]^2 + ans[j]^2 - 2*ans[i]*ans[j] < dp[k] + ans[i]^2 + ans[k]^2 - 2*ans[i]*ans[k];
(dp[j] + ans[j]^2) - (dp[k] + ans[k]^2) < ans[i]*( 2*ans[j] - 2*ans[k]);
若:
(dp[j] + ans[j]^2) => yj
(dp[k] + ans[k]^2) => yk
2*ans[j] => xj
2*ans[k] => xk
则上式为 ( yj - yk ) < a*(xj- xk) 即为斜率
若g[j, k] < a,则j比k更优
若g[j, k] > g[k, l] >a,则k一定不是最优解,可删除,因为g[j, k] > a,则k比j优, 同理,l比k优,故k一定不选
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX(a, b) (a>b?a:b)
#define MIN(a, b) (a<b?a:b)
using namespace std;
const int maxn= 500010;
const int INF= 0x3f3f3f3f;
int dp[maxn], n, m, ans[maxn], que[maxn];
int getx(int j, int k){
return 2*(ans[j] - ans[k]);
}
int gety(int j, int k){
return dp[j] - dp[k] + ans[j]*ans[j] - ans[k]*ans[k];
}
void dynamic(){
int i, j, k, tail, head;
head= 0, tail= -1;
que[++tail]= 0;
for( i= 1; i<= n; i++){
//找到之前最优的j,得dp[i]值
while ( head < tail && gety(que[head+1], que[head]) <= ans[i]*getx(que[head+1], que[head]) )
head++;
dp[i]= dp[que[head]] + (ans[i] - ans[que[head]])*(ans[i] - ans[que[head]])+ m;
//找i存放的位置
while ( head < tail && gety(i, que[tail])*getx(que[tail], que[tail-1]) <= gety(que[tail], que[tail-1])*getx(i, que[tail]))
tail--;
que[++tail]= i;
}
}
int main(){
//freopen("1.txt", "r", stdin);
int i, j, k, aa;
while( scanf("%d%d", &n, &m) != EOF){
ans[0]= 0;
for( i= 1; i<= n; i++){
scanf("%d", &aa);
ans[i]= ans[i-1] + aa;
}
dp[0]= 0;
dynamic();
printf("%d\n", dp[n]);
}
return 0;
}