[POJ]3017 单调队列 + set

来源:互联网 发布:我的世界方块数据值 编辑:程序博客网 时间:2024/06/06 10:08
Cut the Sequence
Time Limit: 2000MS Memory Limit: 131072KTotal Submissions: 10705 Accepted: 3267

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 172 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]

Home Page   Go Back  To top

   嗯...好题. 用到了单调性来优化复杂度.

   首先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"#endifusing 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]);}



原创粉丝点击