【来源】
【题目描述】
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。每段的价值为这段的最大值。如何分割使得所有段的价值总和最小。
【解析】
单调队列优化动态规划。
转移方程:
d
p
[
i
]
=
m
i
n
{
d
p
[
j
]
+
m
a
x
a
[
j
+
1
]
,
a
[
j
+
2
]
.
.
.
a
[
i
]
}
dp[i] = min \{ dp[j] + max{a[j+1], a[j+2] ... a[i]} \}
dp[i]=min{dp[j]+maxa[j+1],a[j+2]...a[i]}
d
p
[
j
−
1
]
+
m
a
x
{
a
[
j
]
.
.
.
a
[
i
−
1
]
}
=
=
d
p
[
j
−
1
]
+
m
a
x
{
a
[
j
]
.
.
.
a
[
i
]
}
dp[j-1] + max\{a[j] ... a[i-1]\} == dp[j-1] + 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;
}