hdu 3415(单调队列) Max Sum of Max-K-sub-sequence

题目链接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
",ans,s,e);
55     }
56     return 0;
57 }
原文地址:https://www.cnblogs.com/JJCHEHEDA/p/5269727.html