P8102 Cow Insertion Solution


听着《打上花火》,不知不觉推出了式子

初碰此题,看见 ,感觉 能过啊

心想可能得卡个常数了(事实后来我是大常数选手

看到题面立马想到插入 的影响是有限的,大概是向左向右 个数。

整个题目都在求 ,干脆将所有 得到的数单独算出来。想到算定长最值,可以用 滑动窗口 解决,所以将值设出来:

那么未插入 的答案即为:

现在考虑插入 之后答案将会变成什么。

如果将 插入到 后面,序列长这个样子:

那么左端没有覆盖到 的地方是不会受 的影响的。

右边界 的右端点刚好与 重合)

所以右边界

所以左端未受影响的答案为

同理,

右端左边界

则右端未受影响的答案为

现在需要处理中间受影响的部分。

观察到覆盖 的地方有个共同点,就是他们对答案的贡献为原长度为 的贡献与

将长度为 结果列出来:

相似。

那么, 的最终贡献为

左边界为 (刚好 踩到原来 的位置)

所以

右边界同理,

所以贡献为:

所以加入 的最终答案为:



此时可以直接通过求出 (需要先进行 操作)的前缀和, 枚举求解

但是,式子有点乱。

,得到加入 的贡献:

于是可以得到一个用 std::vector 实现的超大常数 code:

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <cstdio>
#include <vector>
#include <deque>

// monotony_queue 即 单调队列
std::deque<std::pair<int, int> > dq;
int push_back(int id, int x, int m) {
while (!dq.empty() && dq.back().second <= x) dq.pop_back();
dq.push_back({id, x});
while (!dq.empty() && dq.front().first <= id - m) dq.pop_front();
return dq.front().second;
}
std::vector<int> monotony_queue(std::vector<int> v, int m) {
// init
dq.clear();
std::vector<int> ans;

// main
for (int i = 0; i < m - 1; i++) push_back(i, v[i], m);
for (int i = m - 1; i < v.size(); i++) {
ans.push_back(push_back(i, v[i], m));
}
return ans;
}

#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))

int main() {
static std::vector<int> v, s, u;
int n, m, A, x;

// input
scanf("%d%d%d", &n, &m, &A);
for (int i = 0; i < n; i++) {
scanf("%d", &x);
v.push_back(x);
}

// init s, u
s = monotony_queue(v, m);
u = monotony_queue(v, m - 1);

u[0] = max(u[0], A);
for (int i = 1; i < u.size(); i++) {
u[i] = max(u[i], A);
u[i] += u[i - 1];
}
u.insert(u.begin(), 0);

for (int i = 1; i < s.size(); i++) {
s[i] += s[i - 1];
}
s.insert(s.begin(), 0);

int maxn = -998244353; // ans''
for (int k = 1; k <= n; k++) { // 这里记得算全 k,否则会 WA
int l = max(0, k - m + 1);
int r = min(n - m + 1, k);
maxn = max(maxn, u[r + 1] - u[l] - s[r] + s[l]);
}
maxn += *s.rbegin(); // Don't forget add ans
printf("%d\n", maxn); // ans'
return 0;
}