HDU 3507 Print Article (斜率优化DP)

来源:互联网 发布:js判断数组重复元素 编辑:程序博客网 时间:2024/05/03 00:14

题意:一篇文章打印成多行,每行可以有任意数目个字符,打印成一行的代价为sigma(ci)^2+m,求总的最小代价。

思路:设dp[i]为考虑前i个字符的最小代价,s[i]为从第1个字符到第i个字符的代价和。

那么枚举与第i个字符同行的字符个数得方程:dp[i] = min(dp[i] , dp[j] + (s[i] - s[j])^2 + m)。

然后斜率优化复杂度降到O(n)。

斜率DP个人理解:

在得到一个方程后,设变量k,j(正推k > j,逆推k<j),k比j更优,列出和斜率相关的方程。

斜率上的X,Y为决策点。将X,Y代入原始方程会得到一个直线,再根据具体意义和是否满足单调性来确定维护决策点的凹凸折线。


我的代码:

#include<cstdio>#include<cstring>#include<queue>using namespace std;typedef long long LL;const int maxn = 500005;int n,m,cost[maxn];int dp[maxn],sum[maxn];int que[maxn],head,tail;int getDP(int i,int j){    return dp[j] + (sum[i]-sum[j])*(sum[i]-sum[j]) + m;}int getUp(int i,int j){    return dp[j] + sum[j]*sum[j] - dp[i] - sum[i]*sum[i];}int getDown(int i,int j){    return sum[j] - sum[i];}int main(){    while(~scanf("%d%d",&n,&m)){        for(int i=1;i<=n;i++){            scanf("%d",&cost[i]);            sum[i] = sum[i-1] + cost[i];        }        dp[0] = head = tail = 0;        que[tail++] = 0;        for(int i=1;i<=n;i++){            while(head+1 < tail && getUp(que[head],que[head+1])                  <= 2*sum[i]*getDown(que[head],que[head+1])) head++;            dp[i] = getDP(i,que[head]);            while(head+1 < tail && getDown(que[tail-1],i)*getUp(que[tail-2],que[tail-1])                  >= getUp(que[tail-1],i)*getDown(que[tail-2],que[tail-1])) tail--;            que[tail++] = i;        }        printf("%I64d\n",dp[n]);    }    return 0;}


0 0
原创粉丝点击