zoukankan      html  css  js  c++  java
  • 最大子段和之带长度限制

    带长度限制的最大子段和

    题目模型

    • 一个整数序列(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
      ",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
      ",ans,l,r);
      }
      int main(){
          Solve();
          return 0;
      }
      
    • 习题:[HDU-3415](

  • 相关阅读:
    PHP数字补零的两种方法
    php 防跨站表单提交
    PHP字符串压缩
    原生JS实现表单序列化serialize()
    java并发实现原子操作
    Effective java -- 9 并发/序列化
    Effective java -- 8 异常
    Effective java -- 7 通用程序设计
    Effective java -- 6 方法
    Effective java -- 5 枚举和注解
  • 原文地址:https://www.cnblogs.com/hbhszxyb/p/13130924.html
Copyright © 2011-2022 走看看