Print Article(hdu 3507 斜率dp+单调队列 模板)

题目链接:

Print Article

 

题意:

给定 n 个数 c[i] ,和一个常数 M ,求  (\sum_{i=1}^{k}c[i])^{2}+M 的最小值。

 

思路:

设 sum[i] 表示 c[i] 的前缀和(即c[1]+c[2]+...+c[i])。 (sum[0]=0,表示为空)

设 dp[i] 表示处理到第 i 位时候的最小花费。

dp[i]=min(dp[j]+(sum[i]-sum[j])^2+M) 其中 0<=j<i .

可以看出复杂度为O(n^2),在n<=5e5的情况下无法满足要求。

思考:能不能用更短的时间找到最优的转移点

=> 斜率dp:

假设 i>j>k,计算dp[i]时,若 j 跳转比 k 跳转优秀,那么满足:

dp[j]+(sum[i]-sum[j])^2+M<dp[k]+(sum[i]-sum[k])^2+M

=>

\frac{(dp[j]+sum[j]^{2})-(dp[k]+sum[k]^{2})}{sum[j]-sum[k]}< 2*sum[i]

左边的式子相当于以sum[x]为横坐标,以dp[x]+sum[x]^2为纵坐标的直线的斜率。

经分析,当满足下凸的性质时,最优转移一定在其中。

参考博客:斜率优化dp学习

所以维护这个性质,二分查找斜率比2*S[i]小的编号最大的点,就是最优的转移点O(nlogn)。由于S[i]也满足单调性,我们还可以直接维护一个单调队列就能解决这个问题O(n)。

 

tips:0点是自己构造的一个本不存在的点,相当于坐标系的原点(0,0),作用是能给第一个点一个初始的斜率,便于后续计算。

 

Code:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAX = 500000 + 100;
const ll MOD = 1e9 + 7;

int n, m;
ll sum[MAX];
ll dp[MAX];
ll q[MAX];

//斜率分子
ll up(int j, int k) {
	return (dp[j] + sum[j] * sum[j]) - (dp[k] + sum[k] * sum[k]);
}

//斜率分母
ll down(int j, int k) {
	return sum[j] - sum[k];
}

int main()
{
	while (scanf("%d%d", &n, &m) != EOF)
	{
		for (int i = 1; i <= n; i++) {
			scanf("%lld", &sum[i]);
		}
		for (int i = 1; i <= n; i++) {
			sum[i] += sum[i - 1];
		}
		dp[0] = 0;
		int left = 1, right = 1;
		q[1] = 0;
		for (int i = 1; i <= n; i++) {
			//找到最优跳转点,若无法维护单调队列可用二分
			while (left < right && (up(q[left + 1], q[left]) < 2 * sum[i] * down(q[left + 1], q[left])))
				left++;
			int front = q[left];
			//状态转移
			dp[i] = dp[front] + (sum[i] - sum[front])*(sum[i] - sum[front]) + m;
			//维护下凸性质
			while (left < right&&up(i, q[right])*down(q[right], q[right - 1]) <= down(i, q[right])*up(q[right], q[right - 1]))
				right--;
			q[++right] = i;
		}
		printf("%lld\n", dp[n]);
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值