这题是有下界的最大子段和, 无上下界的最大子段和请看
hh大牛把这个归为单纯的单调队列题, 因为这个状态间不用转移, 其实无所谓啦, 思路都是一样的
思路:
单调队列优化dp
以i结尾的最大子段和 d[i] = max{ sum[i]-sum[k] | k=[i-K , i-1] }.
化为 d[i] = max(f[k])+sum[i]. f[k]=-sum[k], k=[i-k, i-1]. k>=0
另外, 题目是环, 把序列处理成2*n就行了.
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
inline int Rint() { int x; scanf("%d", &x); return x; }
inline int max(int x, int y) { return (x>y)? x: y; }
inline int min(int x, int y) { return (x<y)? x: y; }
#define FOR(i, a, b) for(int i=(a); i<=(b); i++)
#define FORD(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(x) for(int i=0; i<(x); i++)
typedef long long int64;
#define INF (1<<30)
const double eps = 1e-8;
#define bug(s) cout<<#s<<"="<<s<<" "
// 单调队列优化dp
// 以i结尾的最大子段和 d[i] = max{ sum[i]-sum[k] | k=[i-K , i-1] }.
// 化为 d[i] = max(f[k])+sum[i]. f[k]=-sum[k], k=[i-k, i-1]. k>=0
// 另外, 题目是环, 把序列处理成2*n就行了.
#define MAXN 100002*2 //环
int sum[MAXN];
int f[MAXN];
int q[MAXN];
int front, tail;
int main()
{
int T = Rint();
while(T--)
{
sum[0] = 0;
int n = Rint();
int K = Rint();
FOR(i, 1, n)
{
int t = Rint();
sum[i]=sum[i-1]+t;
sum[i+n] = sum[i];
}
FOR(i, 1+n, n+n)
{
sum[i] += sum[n];
}
front = tail = 0;
f[0] = 0;
int maxd = -INF;
int st=1, en=1;
FOR(i, 1, n*2)
{
f[i] = -sum[i];
// 把i-1丢进队列
while(front<tail && f[q[tail-1]]<f[i-1]) tail--;
q[tail++] = i-1;
// 算d[i]
int low = max(i-K, 0);
while(q[front]<low) front++;
int d = f[q[front]]+sum[i];
if(d>maxd)
{
maxd = d;
st = q[front]+1; //这里出现的st , 必小于 n
en = i>n? i-n: i;
}
}
printf("%d %d %d\n", maxd, st, en);
}
}