【C++】Cut the Sequence

【來源】

POJ-3017
vjudge

【題目描述】

Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of the integers in the part is not greater than a given integer M. You are to find a cutting that minimizes the sum of the maximum integer of each part.

【輸入格式】

The first line of input contains two integer N (0 < N ≤ 100 000), M. The following line contains N integers describes the integer sequence. Every integer in the sequence is between 0 and 1 000 000 inclusively.

【輸出格式】

Output one integer which is the minimum sum of the maximum integer of each part. If no such cuttings exist, output −1.

【樣例輸出】

8 17
2 2 2 8 1 8 2 1

【樣例輸出】

12

【數據範圍】

Use 64-bit integer type to hold M.

【題目大意】

給定一個長度爲N的序列,你需要把序列分成很多段。每段的和不能超過M。每段的價值爲這段的最大值。如何分割使得所有段的價值總和最小。

【解析】

單調隊列優化動態規劃。
轉移方程:
dp[i]=min{dp[j]+maxa[j+1],a[j+2]...a[i]}dp[i] = min \{ dp[j] + max{a[j+1], a[j+2] ... a[i]} \}
dp[j1]+max{a[j]...a[i1]}==dp[j1]+max{a[j]...a[i]}dp[j-1] + max\{a[j] ... a[i-1]\} == dp[j-1] + max\{a[j] ... a[i]\}

【代碼】

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

#define RI                 register int
#define re(i,a,b)          for(RI i=a; i<=b; i++)
#define ms(i,a)            memset(a,i,sizeof(a))
#define MAX(a,b)           (((a)>(b)) ? (a):(b))
#define MIN(a,b)           (((a)<(b)) ? (a):(b))

using namespace std;

typedef long long LL;

const int N=1e5+5;
const int inf=1e9;

LL n,m;
LL a[N],dp[N],q[N];

int main() {
	int flag=1;
	scanf("%lld%lld",&n,&m);
	for(int i=1; i<=n; i++) {
		scanf("%lld",&a[i]);
		if(a[i]>m) flag=0;
	}
	if(flag==0) {
		puts("-1");
		return 0;
	}
	int l=0,r=0,p=1;
	LL sum=0;
	dp[0]=0;
	dp[1]=a[1];
	q[r++]=0;
	for(int i=1; i<=n; i++) {
		sum+=a[i];
		while(sum>m) sum-=a[p++];
		while(l<r && q[l]<p) l++;
		while(l<r && a[q[r-1]]<=a[i]) r--;
		q[r++]=i;
		dp[i]=dp[p-1]+a[q[l]];
		for(int j=l; j<r-1; j++) 
			dp[i]=MIN(dp[i],dp[q[j]]+a[q[j+1]]);
	}
	printf("%lld\n",dp[n]);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章