hdu 3415 Max Sum of Max-K-sub-sequence
hdu 3415 Max Sum of Max-K-sub-sequence
//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; }