原题传送:http://acm.hdu.edu.cn/showproblem.php?pid=3415
【题目分析】
因为序列是环状的,所以可以在序列后面复制一段(或者复制前 k 个数字)。如果用 s[i]来表示复制过后的序列的前 i 个数的和,那么任意一个子序列[i..j]的和就等于[j]-s[i-1]。对于每一个 j,用 s[j]减去最小的一个 s[i](i>=j-k+1)就可以得到以 j 为终点长度不大于 k 的和最大的序列了。将原问题转化为这样一个问题后,就可以用单调队列解决了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #define N 200005 4 #define INF 1000000000 5 int a[N], sum[N], q[N]; 6 7 int main() 8 { 9 int n, k, max, i, head, tail, x, y, cas; 10 scanf("%d", &cas); 11 while(cas --) 12 { 13 scanf("%d%d", &n, &k); 14 for(i = 1; i <= n; i ++) 15 { 16 scanf("%d", &a[i]); 17 sum[i] = sum[i - 1] + a[i]; 18 } 19 for(i = n + 1; i < n + k; i ++) 20 sum[i] = sum[i - 1] + a[i - n]; 21 22 max = -INF; 23 for(head = tail = 0, i = 1; i < n + k; i ++) 24 { 25 while(head < tail && q[head] < i - k) 26 head ++; 27 while(head < tail && sum[i - 1] < sum[q[tail - 1]]) 28 tail --; 29 q[tail ++] = i - 1; 30 if(sum[i] - sum[q[head]] > max) 31 { 32 max = sum[i] - sum[q[head]]; 33 x = q[head] + 1; 34 y = i; 35 } 36 } 37 printf("%d %d %d\n", max, x, y > n ? y - n : y); 38 } 39 return 0; 40 }