HDU 3415 Max Sum of Max-K-sub-sequence

HDU_3415

    由于原序列是一个环,为了方便处理可以在序列尾补K-1个元素,从而变成了链。设前i项和为A[i],f[i]为右边界在第i项上时的最大和,则f[i]=max{A[i]-A[j]}(i-K<=j<i),于是我们可以用一个单调队列来维护至今遇到的最小的A[j]即可,且i-K<=j<i。

    由于要求序列非空(或者说要求j<i),所以插入操作要放到最后去做,同时一开始要向队列里插入一个标号为0且值为0的元素。

#include<stdio.h>
#include<string.h>
#define MAXD 200010
#define INF 1000000000
int N, K, f[MAXD], x[MAXD], A[MAXD], q[MAXD], d[MAXD];
void init()
{
int i, j;
scanf("%d%d", &N, &K);
for(i = 1; i <= N; i ++)
scanf("%d", &x[i]);
A[0] = 0;
for(i = 1; i <= N; i ++)
{
A[i] = x[i];
A[i] += A[i - 1];
}
for(i = N + 1; i < N + K; i ++)
{
A[i] = x[i - N];
A[i] += A[i - 1];
}
}
void solve()
{
int i, j, front, rear, a, b, max, sum;
front = rear = 0;
max = - INF;
d[rear] = 0;
q[rear] = 0;
rear ++;
for(i = 1; i < N + K; i ++)
{
while(front < rear && d[front] < i - K)
front ++;
sum = A[i] - A[d[front]];
if(sum > max)
{
max = sum;
a = d[front];
b = i;
}
while(front < rear && q[rear - 1] > A[i])
rear --;
q[rear] = A[i];
d[rear] = i;
rear ++;
}
if(b > N)
b -= N;
printf("%d %d %d\n", max, a + 1, b);
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
init();
solve();
}
return 0;
}


你可能感兴趣的:(sequence)