题目是求环状序列A的一段长度>=k的子序列,使得子序列的和最大。
因为是的环状的,所以将其长度延长k-1。用sum[i]表示a[1]+…+a[i],题目转换成求最大sum[i]-sum[j-1]。因为sum[i]是固定的,因此选择最小的sum[j-1]。不妨考虑用单调队列来优化,维护一个单调递增的队列,记下sum[j-1],每次用队头来更新最大值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| #include <iostream>
using namespace std;
int T, n, k, head, tail, Max, St, Ed, sum[200000], Q[200000], f[200000];
int main()
{
ios::sync_with_stdio(false);
cin >> T;
while (T--)
{
cin >> n >> k;
for (int i = 1; i <= n; ++i)
{
cin >> sum[i];
sum[i+n] = sum[i];
}
for (int i = 1; i < n+k; ++i)
sum[i] += sum[i-1];
Max = 0x80000000;
head = 0, tail = -1;
for (int i = 1; i < n+k; ++i)
{
while (head <= tail && Q[head] < i-k) ++head;
while (head <= tail && sum[i-1]-sum[Q[tail]] <= 0) --tail;
Q[++tail] = i-1;
if (sum[i]-sum[Q[head]] > Max)
{
Max = sum[i]-sum[Q[head]];
St = Q[head]+1;
Ed = (i > n ? i-n : i);
}
}
cout << Max << ' ' << St << ' ' << Ed << endl;
}
}
|