[AGC040E] Prefix Suffix Addition 题解

Description

你有一个长为 NN 的序列 x1,x2,,xNx_1,x_2,\ldots,x_N,一开始全部为 00,你现在可以以任意顺序进行任意次以下两种操作:

  1. 选定整数 k(1kN)k(1\leq k\leq N) 与不下降非负序列 c1,c2,,ckc_1,c_2,\ldots,c_k,对所有 1ik1\leq i\leq k,令 xix_i 加上 cic_i
  2. 选定整数 k(1kN)k(1\leq k\leq N) 与不上升非负序列 c1,c2,,ckc_1,c_2,\ldots,c_k,对所有 1ik1\leq i\leq k,令 xNk+ix_{N-k+i} 加上 cic_i

问最少进行多少次操作使得最后对任意 iixi=Aix_i=A_i

1N2×105,1Ai1091\leq N\leq 2\times 10^5,1\leq A_i\leq 10^9

Solution

首先如果只能做 11 操作,答案就是极长不降段的个数。只有 22 操作答案就是极长不升段的个数。

这启发我们将每个 AiA_i 拆成 aia_ibib_i,分别表示来自 11 操作和 22 操作的贡献,答案即为:i=1N+1([ai<ai1]+[bi>bi1])\sum_{i=1}^{\color{red}{N+1}}{\left([a_i<a_{i-1}]+[b_i>b_{i-1}]\right)}

考虑 dp。

fi,jf_{i,j} 表示考虑了前 ii 个数,满足 ai=j,bi=Aija_i=j,b_i=A_i-j 的最小操作数。

直接转移是 O(nV)O(nV) 的,但是注意到 fi,jf_{i,j} 不升,且 fi,aifi,02f_{i,a_i}\geq f_{i,0}-2,所以用记录一下三种值对应的区间即可。

时间复杂度:O(n)/O(nlogV)O(n)/O(n\log V)

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
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 2e5 + 5;

int n;
int a[kMaxN];

void dickdreamer() {
std::cin >> n;
for (int i = 1; i <= n; ++i) std::cin >> a[i];
// int val = 2, f0 = a[1], f1 = a[1] + 1, f2 = a[1] + 1;
int val = 0, f0 = 0, f1 = 1, f2 = 1;
std::function<int(int)> getreal = [&] (int x) -> int {
if (x >= f2) return 1e9;
if (x <= f0) return val;
else if (x <= f1) return val - 1;
else return val - 2;
};
for (int i = 1; i <= n + 1; ++i) {
int _val, _f0, _f1;
std::function<int(int, int)> getcoef = [&] (int v1, int v2) -> int {
return (v1 > v2) + (a[i - 1] - v1 < a[i] - v2);
};
std::function<int(int)> calc = [&] (int x) -> int {
return std::min({getreal(0) + getcoef(0, x), getreal(f0 + 1) + getcoef(f0 + 1, x), getreal(f1 + 1) + getcoef(f1 + 1, x)});
};
_val = calc(0), _f0 = 0;
int L = 0, R = a[i] + 1;
while (L + 1 < R) {
int mid = (L + R) >> 1;
if (calc(mid) >= _val) L = _f0 = mid;
else R = mid;
}
L = _f1 = _f0, R = a[i] + 1;
while (L + 1 < R) {
int mid = (L + R) >> 1;
if (calc(mid) >= _val - 1) L = _f1 = mid;
else R = mid;
}
// std::cerr << i << ' ' << _val << ' ' << _f0 << ' ' << _f1 << " : \n";
// for (int j = 0; j <= a[i]; ++j) std::cerr << calc(j) << ' ';
// std::cerr << '\n';
// if (_f0 <= a[i]) assert(calc(_f0) == _val && calc(_f0 + 1) != _val);
// if (_f1 <= a[i]) assert(calc(_f1) == _val + 1);
val = _val, f0 = _f0, f1 = _f1, f2 = a[i] + 1;
}
std::cout << val << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

[AGC040E] Prefix Suffix Addition 题解
https://sobaliuziao.github.io/2025/02/20/post/ada3a35f.html
作者
Egg_laying_master
发布于
2025年2月20日
许可协议