最大子段和之带长度限制

带长度限制的最大子段和

题目模型

  • 一个整数序列\(a_1,a_2,……,a_n\) ,求最大的长度不超过K的子段的数值和。

问题分析

  • 求以a[i]结尾的最大子段和,我们需要维护一个最小的前缀sum[j],即[j+1,i]为所求。

  • 但要求子段和区间长度不能大于K,则需要满足:i-j<=k

  • 如果j'>jsum[j']<sum[j],显然sum[j]对后面的求解就没有用了,所以我们可以用一个单调队列维护最远不超过K的最小前缀和。

  • Code

    #include <bits/stdc++.h>
    const int maxn = 1e5+5,Inf=0x3f3f3f3f;
    typedef long long LL;
    int a[maxn<<1],sum[maxn<<1];
    void Solve(){
    	int n,k;	
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;++i){
    		scanf("%d",&a[i]);
    		sum[i]=sum[i-1]+a[i];//前缀和
    	}
    	int ans=-Inf,l,r;//l:记录答案左边界,r:记录右边界
    	std::deque<int> q;//双端队列维护的
    	for(int i=1;i<=n;++i){
            //因为区间[l,r]和为sum[r]-sum[l-1]所以要维护最小的sum[l-1]
    		while(!q.empty() && sum[i-1]<sum[q.back()]) q.pop_back();
            //保证最远的左端点离i的距离不能超过k
    		while(!q.empty() && i-q.front()>k) q.pop_front();
    		q.push_back(i-1);//当前队列要么为空,要么队尾前缀和小于su[i-1]
    		if(sum[i]-sum[q.front()]>ans){
    			ans=sum[i]-sum[q.front()];
    			l=q.front()+1;//注意左边界要+1
    			r=i;
    		}
    	}
    	printf("%d %d %d\n",ans,l,r);
    }
    int main(){
    	Solve();
    	return 0;
    }
    
  • Code手摸双端队列版,建议大家手写队列

    #include <bits/stdc++.h>
    const int maxn = 1e5+5,Inf=0x3f3f3f3f;
    typedef long long LL;
    int a[maxn<<1],sum[maxn<<1],q[maxn<<1];
    void Solve(){
        int n,k;   
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        int ans=-Inf,l,r;
        int head=0,tail=0;
        for(int i=1;i<=n;++i){
            while(head<tail && sum[i-1]<sum[q[tail-1]]) tail--;
            while(head<tail && i-q[head]>k) head++;
            q[tail++]=i-1;//tail指向队尾的后一个位置
            if(sum[i]-sum[q[head]]>ans){
                ans=sum[i]-sum[q[head]];
                l=q[head]+1;
                r=i;
            }
        }
        printf("%d %d %d\n",ans,l,r);
    }
    int main(){
        Solve();
        return 0;
    }
    
  • 习题:[HDU-3415](

posted @ 2020-06-15 14:51  ♞老姚♘  阅读(908)  评论(0编辑  收藏  举报