真的是一道非常棒的题目,我脑袋不怎么灵光,但是五个小时彻底弄懂还是相当值的!
Cut the Sequence
Time Limit: 2000MS Memory Limit: 131072K
Total Submissions: 11054 Accepted: 3382
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
注意:POJ的数据水掉了,导致一些n^2复杂度的算法也可以通过,但是我们本着过的态度做题是毫无意义的。。。
我的LaTeX公式格式写得不好,所以就直接手写了。
有三点需要我们关注:
1.是否符合决策单调性——不符合。
2.如何维护区间最值——单调队列。
3.如何进行时间复杂度优化——平衡树。
本胖头鱼学长blog,LaTeX版本。http://www.cnblogs.com/zufezzt/p/8821194.html
在学长的指引下,终于理解了这道题,看来我的DP才刚刚入门!!!
下面用f数组代表dp数组。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<set>
using namespace std;
#define ll long long int
#define INF 0x3f3f3f3f
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
const int maxn = 1e5 + 10;
int q[maxn], a[maxn], n;
ll m, sum[maxn], f[maxn];
int main()
{
scanf("%d%lld", &n, &m);
sum[0] = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + a[i];
if (a[i] > m) {
puts("-1"); return 0;
}
}
multiset<ll> s; int l = 1, r = 0, k = 0;
for (int i = 1; i <= n; i++) {
while (sum[i] - sum[k]>m) {
k++;
}
while (l <= r && q[l] <= k) {//维护的id在k之前,无效数据抹去
if (r > l) {
s.erase(f[q[l]] + a[q[l+1]]);
}
l++;
}
while (l <= r && a[i] >= a[q[r]]) {//维护递减单调队列
if (r > l) {
s.erase(f[q[r - 1]] + a[q[r]]);
}
r--;
}
q[++r] = i;
f[i] = f[k] + a[q[l]]; ll tmp;
if (l<r&&i>q[r - 1]) {
s.insert(a[i] + f[q[r - 1]]);
}
if (s.size() && i > q[r - 1] && l < r) {
tmp = *s.begin();
}
else {
tmp = INF;
}
if (l < r)
f[i] = min(f[i], tmp);
}
/*for (int i = 1; i <= n; i++) {
printf("%lld ", f[i]);
}*/
printf("%lld\n", f[n]);
return 0;
}