您的位置:首页 > 产品设计 > UI/UE

POJ 3017 Cut the Sequence(单调队列+set)

2013-05-08 12:39 351 查看
Cut the Sequence

Time Limit: 2000MSMemory Limit: 131072K
Total Submissions: 7972Accepted: 2287
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

这题是很好的题目。
思考了很久一直没有想通。
后来突然理解了
可以参照大牛的解释:
/article/4928426.html
这讲得比较详细了。

/*
* 用dp[i]表示前i项进行划分得到的结果
* dp[i]=min{dp[j],max[j+1,i]};
* 首先假如不考虑m的限制。
* 那么最优决策的那个j点,一定满足a[j] > max(a[j+1~i])就是j点的值要大于j+1到j点的值。
* 很明显的结论,因为假如不成立,那么可以把j点也划分到后面去,得到更优的
* 所以用单调队列维护一个递减数列     a1 a2 a3 a4  ...  a[i] ;a1>a2>a3>a4>a[i];
* 这样的话最优决策点只能出现在这些点中。
* 现在加了m的限制。假如上面那个递减数列只有后面一部分是满足m限制的 at,at+1,...a[i].
* 那么决策点就是上面这些点再加上满足m条件的那个边界。
* 所以可以用平衡二叉树维护
* 二叉树里面的值只要随着队列进行维护就好了。
* 可以用multiset实现。
*/

#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <set>
using namespace std;
const int MAXN=100010;
int a[MAXN];
long long sum[MAXN];
int n;
long long m;
int q[MAXN];
int d[MAXN];
multiset<long long>st;
multiset<long long>::iterator it;
long long dp[MAXN];
void solve()
{
int rear,front;
rear=front=0;
int decision=0;//限制条件
st.clear();
for(int i=1;i<=n;i++)
{
while(sum[i]-sum[decision]>m)decision++;
while(front<rear && q[front]<=decision)//让不符合条件的退出队列
{
it=st.find(dp[d[front]]+a[q[front]]);
st.erase(it);
front++;
}
while(front<rear && a[i]>=a[q[rear-1]])//维护单调队列
{
it=st.find(dp[d[rear-1]]+a[q[rear-1]]);
st.erase(it);
rear--;
}
q[rear]=i;
if(front<rear)d[rear]=q[rear-1];
else d[rear]=decision;
st.insert(dp[d[rear]]+a[i]);
rear++;
if(d[front]<decision)//更新那个限制点
{
it=st.find(dp[d[front]]+a[q[front]]);
st.erase(it);
d[front]=decision;
st.insert(dp[decision]+a[q[front]]);
}
it=st.begin();//最小值
dp[i]=(*it);
}
printf("%I64d\n",dp
);
}
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
while(scanf("%d%I64d",&n,&m)==2)
{
bool flag=true;
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
if(a[i]>m)flag=false;
}
if(!flag)
{
printf("-1\n");
continue;
}
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: