//hdu 3415 Max Sum of Max-K-sub-sequence
//单调队列
//题意是说给出一串数字,形成环,求长度小于等于k的子串中的最大子串和
//思路:用数组num[i]保存前i个数的和,由于 1<=K<=N,所欲数组继续延伸到2n个元素
//就可以忽视环。让后维护一个单调队列,使之保存 i-k到 i-1之间最小 子串和,
//从而,num[i] - que[head] 就是 i-k 到 i 之间的最大子串和
#include <stdio.h>
#include <string.h>
#define N 100005
#define INF 1<<30
int num[N*2], que[N*2];
int main()
{
int n_case;
scanf("%d", &n_case);
while(n_case--)
{
int n, k;
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &num[i]);
num[n+i] = num[i];
}
n *= 2; // 1<=K<=N, so 2*n is enough
for(int i = 2; i <= n; ++i)
num[i] += num[i-1];
int ans = -INF, left = 0, right = 0;
int head = 1, tail = 0;
for(int i = 1; i <= n; ++i) //求 i 之前满足条件的最大子串和
{
while(tail >= head && num[i-1] < num[ que[tail] ])//若第i-1 个数小于
tail--; //队尾的数则舍去队尾,因为第i-1个数比队尾新 而且比它小
que[++tail] = i-1;
while(que[head] < i-k)
head++;
if(ans < num[i] - num[ que[head] ])
{
ans = num[i] - num[ que[head] ];
// if(num[ que[head] ] < 0) //不需要这个判断,因为单调队列讨论的是
left = que[head] + 1; //从num[0]开始的,而这个值为0;若这个大于0
// else //则可能是因为num[que[head]]这段和已过期了,如-1 1 2 3 4 5
// left = que[head]; //想一想就知道了,我也说不清
right = que[tail];
}
}
right = right > n/2 ? right - n/2 : right;
printf("%d %d %d\n", ans, left, right+1);
}
return 0;
}