【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;
}