2013寒假练习 1011 Maximum Sum II

来源:互联网 发布:灵飞经版本推荐知乎 编辑:程序博客网 时间:2024/06/01 07:12

地址:http://acm.bit.edu.cn/mod/programming/view.php?a=497

题意:子段长度不超过k的最大子段和。

看似简单题,序号又靠前,结果就给虐了T T

一开始妄图用和最大子段和差不多的方法做,最后才发现算法不对。

正解如下:

sum[i]表示前i个数之和(特别的sum[0]=0),问题转化为找一个最小的sum[j](i-k=<j<i),因为sum[i]-sum[j]即使从j+1到i这个子段的和,故对于当前i,问题转化为找一个最小的sum[j](i-k=<j<i)。直接二重循环会TLE,我们要想办法用O(1)的时间找出最小的sum[j],这实际上是一个移动窗口最值问题,参考http://yzmduncan.iteye.com/blog/1545671,可以用单调队列实现。具体对于这题就是每次将sum[i-1]入队,同时通过删除队尾元素保持队列递增;也将队头的无用元素删掉,找最小值时永远是队头元素最小。具体参看以上链接。

#include<iostream>#include<deque>using namespace std;int sum[50005],ans;int main(){int t,n,k,i,temp;scanf("%d",&t);while(t--){sum[0]=0;scanf("%d%d",&n,&k);for(i=1;i<=n;i++){scanf("%d",&temp);sum[i]=sum[i-1]+temp;}deque<int>q;ans=sum[1];for(i=1;i<=n;i++){while(!q.empty()&&sum[i-1]<=sum[q.back()]) q.pop_back();while(!q.empty()&&q.front()<i-k) q.pop_front();q.push_back(i-1);if(sum[i]-sum[q.front()]>ans) ans=sum[i]-sum[q.front()];}printf("%d\n",ans);}return 0;}


 

 

原创粉丝点击