题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3415
题目大意:
给n个数凑成环状,求某一区间,使得该区间长度不超过k,且总和最大。
解题思路:
区间总和,很容易想到保存前缀和,区间【i,j】的和即为sum[j]-sum[i].
对于每一个以j结束的区间,求出最小的i,(i>=j-k),也即使得sum[j]-sum[i]最大。
所以可以用单调队列维护一个最小的sum[i],对于每一个j,压进j-1.(因为是要减去前面的)
代码:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 110000 int sa[Maxn]; int sum[Maxn<<1]; int q[Maxn<<1]; int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,n,k; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&k); sum[0]=0; for(int i=1;i<=n;i++) { scanf("%d",&sa[i]); sum[i]=sum[i-1]+sa[i]; } for(int i=n+1;i<n+k;i++) sum[i]=sum[i-1]+sa[i-n]; //n+=k-1; int head=0,tail=0,s,e; int ans=-INF; q[0]=0; for(int i=1;i<n+k;i++) { while(head<=tail&&sum[i-1]<=sum[q[tail]])//保证最短 tail--; q[++tail]=i-1; while(q[head]+1<i-k+1) head++; if(sum[i]-sum[q[head]]>ans)//保证初始位置最小 { ans=sum[i]-sum[q[head]]; s=q[head]+1; e=i; } } printf("%d %d %d ",ans,s,e>n?e%n:e); } return 0; }