【來源】
【題目描述】
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。每段的價值爲這段的最大值。如何分割使得所有段的價值總和最小。
【解析】
單調隊列優化動態規劃。
轉移方程:
【代碼】
#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;
}