【POJ】3017Cut the Sequence(单调队列)

【POJ】3017Cut the Sequence(单调队列)

Time Limit: 2000MS
Memory Limit: 131072K

Description

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.

Input

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

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

Sample Input

8 17
2 2 2 8 1 8 2 1

Sample Output

12

Hint

Use 64-bit integer type to hold M.

思路

用前缀和。
DP:
f[i]=min(f[j]+max(f[k]))1<=i<=n,1<=j<i,j<k<i
用单调队列优化

代码

#include<iostream>
#include<cstdio>
#include<deque>
using namespace std;
long long a[100010],sum[100010],ans[100010];
deque<long long> que,temp;
long long read()//快读 
{
    
    
	long long ans=0,f=1;
	char c;
	for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
	if(c=='-') f=-1;
	else ans=c-48;
	for(c=getchar();'0'<=c&&c<='9';c=getchar())ans=(ans<<3)+(ans<<1)+c-48;
	return ans*f;
}
int main()
{
    
    
	long long i,j,n,m,k=1,tem;
	n=read(),m=read();
	for(i=1;i<=n;i++)
	{
    
    
		a[i]=read();
		if(a[i]>m)
		{
    
    
			putchar('-'),putchar('1');
			return 0;
		}
		sum[i]=sum[i-1]+a[i];//前缀和 
	}
	for(ans[1]=a[1],i=1;i<=n;i++)
	{
    
    
		for(;!que.empty()&&a[i]>=a[que.back()];que.pop_back());//删除小于a[i]的数
		for(que.push_back(i);sum[i]-sum[k-1]>m&&k<i;k++);
		for(;!que.empty()&&que.front()<k;que.pop_front());//找不在范围内数
		for(ans[i]=ans[k-1]+a[que.front()],j=que.size()-1;j>0;j--)
			ans[i]=min(ans[i],ans[que[j-1]]+a[que[j]]);
	}
	printf("%lld",ans[n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_46975572/article/details/113122489