HDU 3415 Max Sum of Max-K-sub-sequence

题目链接

题目大意:

我们有一个环状的数列,内有n个元素,现在其中找一长度不超过k的连续子序列,使值最大.

分析:

原数组断环为链:

\(A_1\)..\(A_n\) = > \(A_1\).. \(A_n A_{n+1}\)..\(A_{n+k}\)

考虑一段连续的子序列的值就是前缀和相减的形式

我们得到前缀和数组

\(S_1\)..\(S_{n+k}\)

考虑以i为右端点的子序列,共有k种,值分别是\(S_i-S_{i-1}\),\(S_i-S_{i-2}\)...\(S_i-S_{i-k}\)

显然我们要在这之中找一个最大值,即在\(S_{i-1}\),\(S_{i-2}\)...\(S_{i-k}\)中找一个最小值

问题转化成对于每个\(S_i\),在某一定长区间内找一最小值

ST表,线段树均可在\(O(nlogn)\)的时间内解决

但是还可以更快,用单调队列

[Code]


#include <bits/stdc++.h>
using namespace std;

int read(){
	int x=0,flag=1; char c;
	for(c=getchar();!isdigit(c);c=getchar()) if(c=='-') flag=-1;
	for(;isdigit(c);c=getchar()) x=((x+(x<<2))<<1)+(c^48);
	return x*flag;
}

const int N=2e5+50;

int n,k;
int a[N];
int s[N];

int main() {
    int T=read();
    while(T--){
	    n=read(),k=read();
	    for(int i=1;i<=n;i++) a[i]=read();
	    for(int i=n+1;i<=n+k+1;i++) a[i]=a[i-n];
	    for(int i=1;i<=n+k+1;i++) s[i]=s[i-1]+a[i];
	    
	    int ans=-2e9;
	    int l=-1,r=-1;
	    
	    deque<int> q;
	    q.push_back(0);
	    for(int i=1;i<=n+k+1;i++){
		    while(!q.empty()&&i-q.front()>k) q.pop_front();
		    if(s[i]-s[q.front()]>ans){
			    ans=s[i]-s[q.front()];
			    l=q.front()+1; r=i;
			}
			ans=max(ans,s[i]-s[q.front()]);
		    while(!q.empty()&&s[q.back()]>=s[i]) q.pop_back();
		    q.push_back(i);
		}

        if(l>n) l-=n;
        if(r>n) r-=n;
		
		printf("%d %d %d\n",ans,l,r);
	}
	return 0;
}

posted @ 2020-01-21 15:14  zhuzihan  阅读(82)  评论(0编辑  收藏  举报