Cut the Sequence
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. Source
POJ Monthly--2006.09.29, zhucheng
|
维护一个递减的队列,存的是符合要求的某一段的最大值,
代码如下:
#include <iostream> #include<string.h> #include<stdio.h> #define MIN(a,b) ((a)<(b)?(a):(b))//第一次用感觉还不错 using namespace std; struct node { int val;//存单调队列的值 int id;//存队列元素的下标 } q[100100]; int a[100100],head,tail,down; int n; __int64 dp[100100],sum,m; int main() { int i,j,p,flag; while(~scanf("%d%I64d",&n,&m)) { for(i=1; i<=n; i++) scanf("%d",a+i); memset(dp,0,sizeof dp); sum=0; down=1;//down维护 head=tail=0; flag=1; q[tail].val=-1; for(i=1; i<=n; i++)//计算以i结尾的最大值和的最小值 { sum+=a[i]; while(sum>m)//满足和不大于m的区间为low到i。做法很经典。 sum-=a[down++];//减去前面的值使和满足条件。down为左边界。 if(down>i) { flag=0; break; } while(tail>=head&&a[i]>q[tail].val)//将新元素入队 tail--; q[++tail].id=i; q[tail].val=a[i]; while(q[head].id<down)//剔除队列中超过范围的元素 head++; dp[i]=dp[down-1]+q[head].val; for(j=head; j<tail; j++) { p=q[j].id; dp[i]=MIN(dp[i],dp[p]+q[j+1].val);//做法很经典! } } if(flag) printf("%I64d\n",dp[n]); else printf("-1\n"); } return 0; }