AT_agc040_e
很有意思的题。
首先考虑只有操作 \(1\),则答案显然 \(\ge \sum\limits_{i=1}^{n} [a_i > a_{i + 1}]\),即划分出最少的不降子段,同时每个子段又可以被一次操作消除,所以答案为 \(\sum\limits_{i=1}^{n} [a_i > a_{i + 1}]\)。
对于只有操作 \(2\),同理,答案为划分出最少的不升子段的个数。
然后考虑把这两种结合起来,考虑把 \(a\) 序列拆成两个序列 \(p, q\),满足 \(\forall i, a_i = p_i + q_i\),我们要求 \(p\) 只能用操作 \(1\) 消除,\(q\) 只能用操作 \(2\) 消除,那么把 \(p\) 和 \(q\) 消除完的方案数之和就是最终方案数。
考虑大力 DP,\(f_{i, j}\) 表示 \(p_i = j\),前 \(i\) 个数最少要操作多少次,则
化简一下,得到
容易发现 \(j\) 越小,越容易满足中括号里的条件,也就是说 \(f_{i, j}\) 关于 \(j\) 单调不增。另外,对于 \(f_{i, 0}\),肯定是从某个 \(f_{i - 1, k} + C_1(0 \le C_1 \le 2)\),那么 \(f_{i, a_i}\) 也可以从 \(f_{i - 1, k} + C_2(0 \le C_2 \le 2)\) 转移来,由于 \(C_1 \le C_2 + 2\),所以 \(f_{i, 0} \le f_{i, a_i} + 2\),也就是说 \(f_{i, j}\) 被 \(j\) 分成了三个不同的值域段。
于是枚举 \(i\),记 \(d = f_{i - 1, a_i}\),那么肯定存在两个分界点 \(p \le q\),使得
这里认为 \([l, r](l > r) = \varnothing\)。
于是每次考虑 \(p, q, d\) 的变化即可,这只和 \(a_i - a_{i - 1}\) 有关,时间复杂度 \(\mathcal{O}(n)\)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
// typedef __int128 i128;
typedef pair<int, int> pii;
const int N = 2e5 + 10, mod = 998244353;
template<typename T>
void dbg(const T &t) { cout << t << endl; }
template<typename Type, typename... Types>
void dbg(const Type& arg, const Types&... args) {
cout << arg << ' ';
dbg(args...);
}
namespace Loop1st {
int n, d, p = -1, q = -1, a[N];
void main() {
cin >> n;
for (int i = 1; i <= n + 1; i++) {
cin >> a[i];
int del = a[i] - a[i - 1];
if (del >= 0) {
p = min(q, p + del);
q += del;
} else {
p = min(p, q + del); p = max(p, -1);
if (q >= a[i]) {
d++;
q = p; p = -1;
}
}
}
cout << d << '\n';
}
}
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T = 1;
// cin >> T;
while (T--) Loop1st::main();
return 0;
}

浙公网安备 33010602011771号