您的位置:首页 > 其它

poj 3017 dp+单调队列优化

2012-09-18 14:51 351 查看
/*
题意:给你一个长度为n的数列,要求把这个数列划分为任意块,每块的元素和小于m,使得所有块的最大值的和最小
分析:这题很快就能想到一个DP方程 f[ i ]=min{ f[ j ] +max{ a[ k ] }}( b[ i ]<j<i,j<k<=i)     b[ i ]到 i的和大于m
这个方程的复杂度是O(n^2),明显要超时的(怎么discuss都说数据弱呢= =)
然后是优化了,首先当然是要优化一个最大值的队列,使得这个队列的队首元素的到当前位置的和不超过m,
这样一个可行解就是,f[ i ]=f[b[ i ]-1]+a[ q[ l ]](即队首元素的值),
这并不是最优解,所以还要找到队列中的最优解,一个可能的最优解只能是这样的
f[ q[ j ] ]+ a[ q[j +1 ]],也就是 a[ j ] 要大于后面的数,
很显然,如果a[ j ]小于后面的数,那么我们就可以将 a[ j ] 划分到后面去,而取得更优解
这里涉及的这个找最优解问题,
因为一个m 定义成int WA了无数次。。。。伤不起!!!
*/
#include<iostream>
#include<algorithm>
#include<set>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=110002;
int q[maxn],a[maxn],pre,n;
__int64 sum,Max[maxn],m;
int main()
{
scanf("%d%I64d",&n,&m);
int i,j,l=0,r=-1,flag=0;
pre=1,sum=0;
Max
=-1;
multiset<int>s;
s.clear();
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
sum+=a[i];
while(sum>m) sum-=a[pre++];
if(a[i]>m) flag=1;
if(flag) continue;
while(l<=r&&a[i]>=a[q[r]])
{
if(l<r)s.erase(Max[q[r-1]]+a[q[r]]);
r--;
}
q[++r]=i;
if(l<r) s.insert(Max[q[r-1]]+a[q[r]]);
while(q[l]<pre)
{
if(l<r)s.erase(Max[q[l]]+a[q[l+1]]);
l++;
}
Max[i]=Max[pre-1]+a[q[l]];
__int64 ans=*s.begin();
if(l<r&&Max[i]>ans) Max[i]=ans;
}
if(flag) printf("-1\n");
else
{
printf("%I64d\n",Max
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: