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
|
[Submit] [Go Back] [Status] [Discuss]
嗯...好题. 用到了单调性来优化复杂度.
首先dp方程很容易得到. f[i] = min(f[j] + max(f[j + 1] + f[j + 2]....f[i])). 因为所有值都为非负数, 所以f[1] <= f[2] <= f[3]. 所以对于i来说, 如果j, j + 1, j + 2 ... k到i的最大值是相同的话, 肯定取f[j - 1](最大值是从j开始算的)是最优的. 而且又因为从1, 2, 3, ... i-1, i 到i的最大值肯定是单调不上升的, 那么用一个单调递减的维护最大值的位置, 然后当前 最大值+单调队列里上一个最大值的点的f(从上一个的之后最大值就是当前的, 所以相同最大值肯定要维护最后出现的, 所以单调递减, 而非不上升). 插入multiset里面求最小值即可(单调队列队首只是最大最大值,不代表是最优解) . 注意特判有点多.
#include<stdio.h>
#include<set>
#ifdef WIN32
#define aut "%I64d"
#else
#define aut "%lld"
#endif
using namespace std;
multiset<int> s;
const int maxn = 100005;
typedef long long dnt;
bool flag;
int n, a[maxn], q[maxn];
dnt temp, f[maxn], m, sum;
int main(){
scanf("%d"aut, &n, &m);
flag = true;
for(int i = 1; i <= n; ++i){
scanf("%d", &a[i]);
if(a[i] > m) flag = false;
}
if(!flag) {puts("-1"); return 0;}
int low = 1, h = 1, t = 0;
for(int i = 1; i <= n; ++i){
sum += a[i];
while(sum > m) sum -= a[low], ++low;
while(h <= t && a[q[t]] <= a[i]){
if(t > h) s.erase(f[q[t - 1]] + a[q[t]]);
--t;
}
q[++t] = i;
if(t > h) s.insert(f[q[t - 1]] + a[q[t]]);
while(low > q[h]){
if(t > h) s.erase(f[q[h]] + a[q[h + 1]]);
++h;
}
temp = *(s.begin()), f[i] = f[low - 1] + a[q[h]];
if(h < t && temp < f[i]) f[i] = temp;
}
printf(aut, f[n]);
}