题目链接http://acm.hdu.edu.cn/showproblem.php?pid=3415
大意是给出一个有n个数字的环状序列,让你求一个和最大的连续子序列。这个连续子序列的长度小于等于k。
由于是环状的数列,一般采取的措施是在数列的后面再复制一部分前面的数列;a[n]=a[0],a[n+1]=a[1]----
用sum数组存储前i个数的和,那么对于j属于范围(i-k,i-1)来说,最大连续子序列就等于sum[i]减去在该范围内最小的sum[j]
那么问题就变成了求在每k个范围内最小的sum[i]就行,那么就需要用到单调队列来求,队列是一个单调递增的队列,再记录一
下区间的下标就行。
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 const int M=210000; 5 const int inf=0x3f3f3f3f; 6 int sum[M],a[M]; 7 int main() 8 { 9 int t,n,k,i; 10 scanf("%d",&t); 11 while (t--){ 12 scanf("%d %d",&n,&k); 13 sum[0]=0; 14 for (i=1;i<=n;i++){ 15 scanf("%d",&a[i]); 16 sum[i]=sum[i-1]+a[i]; 17 } 18 for (i=n+1;i<n+k;i++){ 19 a[i]=a[i-n]; 20 sum[i]=sum[i-1]+a[i]; 21 } 22 n+=k-1; 23 int ans=-inf,s,e; 24 deque<int>q; 25 q.clear(); 26 for (i=1;i<=n;i++){ 27 while (!q.empty()&&q.front()<i-k) 28 q.pop_front(); 29 while (!q.empty()&&sum[i-1]<sum[q.back()]) 30 q.pop_back(); 31 q.push_back(i-1); 32 if (ans<sum[i]-sum[q.front()]){ 33 ans=sum[i]-sum[q.front()]; 34 s=q.front()+1; 35 e=i; 36 } 37 }//回转换成下面的数组也行 38 /* 39 int ans=-inf,s,e,c=1,d=0; 40 for (i=1;i<=n;i++){ 41 while (d-c>=0&&b[c]<i-k) 42 c++; 43 while (d-c>=0&&sum[i-1]<sum[b[d]]) 44 d--; 45 b[++d]=i-1; 46 if (ans<sum[i]-sum[b[c]]){ 47 ans=sum[i]-sum[b[c]]; 48 s=b[c]+1; 49 e=i; 50 } 51 } 52 */ 53 if (e>n-k+1) e%=(n-k+1); 54 printf("%d %d %d\n",ans,s,e); 55 } 56 return 0; 57 }