http://acm.hdu.edu.cn/showproblem.php?pid=3415
本题是需要单调队列的动态规划问题,求环上长度为K以内的且和最大的区间。
单调队列的队头维护的是满足在区间内部的且和最小的下标,这样才能得到最大和sum,因为和是sum[i] - sum[Q.front()]。使用双端队列实现单调队列单调性的维护。a的下标入队时依次弹出比a大的所有元素再将a的下标从队尾加入队列,以维持队列的单调性。
实现如下:
for(int i=1; i<=N; i++){
while(!Q.empty() && sum[i -1] < sum[Q.back()])
Q.pop_back();
while(!Q.empty() && Q.front() < i - K)
Q.pop_front();
Q.push_back(i - 1);
}
AC代码参考:
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int a[200010],sum[200010];
int main(){
// freopen("in.txt","r",stdin);
int cas;
scanf("%d",&cas);
while(cas--){
int N,K;
scanf("%d%d",&N,&K);
sum[0] = 0;
for(int i=1; i<=N; i++){
scanf("%d",&a[i]);
sum[i] = a[i] + sum[i - 1];
}
for(int i=N+1; i<N+K; i++)
sum[i] = sum[i - 1] + a[i - N];
int temp = N;
N = N + K - 1;
deque <int> Q;
Q.clear();
int ans = -INF,start,en;
for(int i=1; i<=N; i++){
while(!Q.empty() && sum[i - 1] < sum[Q.back()])
Q.pop_back();
while(!Q.empty() && Q.front() < i - K)
Q.pop_front();
Q.push_back(i - 1);
if(sum[i] - sum[Q.front()] > ans){
ans = sum[i] - sum[Q.front()];
start = Q.front() + 1;
en = i;
}
}
if(en > temp)
en %= temp;
cout << ans << " " << start << " " << en << endl;
}
return 0;
}