题解:P14558 [ROI 2013 Day2] 大规模预测
LostKeyToReach · · 题解
蠢蠢根号分治做法。
考虑对
故可以取
对于
这就等价于对于每个
-
$$ \sum_{k < j, p_k < p_j} 1 = \sum_{k < j - 1, p_k < p_{j - 1}} 1 + \sum_{k < j, p_k = p_{j - 1}} 1. $$ -
$$ \sum_{k < j, p_k < p_j} 1 = \sum_{k < j - 1, p_k < p_{j - 1}} - \sum_{k < j, p_k = p_j} 1. $$
单次可以
这个题就做完了,时间复杂度
/*
* author: LostKeyToReach
* created time: 2025-12-01 18:00:19
*/
#include <bits/stdc++.h>
// #define int long long
#define vt std::vector
#define vi vt<int>
#define eb emplace_back
using ll = long long;
using pii = std::pair<int, int>;
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define S std::cin.tie(0)->sync_with_stdio(0)
#define chkmax(x, y) x = std::max(x, y)
#define chkmin(x, y) x = std::min(x, y)
int fio = (S, 0);
constexpr int N = 1e6 + 5, base = 5e5, B = 150;
int n, k, v[N], cnt[N], h[N], nxt[N], lst[N], clr[N], tot;
int32_t main() {
std::cin >> n >> k;
for (int i = 1; i <= n; ++i)
std::cin >> v[i], ++cnt[v[i]];
for (int i = 1; i <= n; ++i) if (cnt[v[i]] > B)
h[v[i]] = 1;
for (int i = 1; i <= n; ++i) cnt[v[i]] = 0, lst[v[i]] = n + 1;
for (int i = n; i >= 1; --i)
nxt[i] = lst[v[i]], lst[v[i]] = i;
long long ans = 0;
for (int l = 1; l <= n; ++l) {
for (int i = l, t; i <= std::min(n, l + 2 * B - 1); ++i) {
if (h[v[i]]) continue;
if ((t = ++cnt[v[i]]) == 1) clr[++tot] = v[i];
ans += std::max(0ll, (ll)std::min(l + t * 2 - 2, nxt[i] - 1) - i + 1);
}
for (int i = 1; i <= tot; ++i) cnt[clr[i]] = 0;
tot = 0;
}
for (int i = 1; i <= k; ++i) if (h[i]) {
clr[tot = 1] = base;
long long cur = 0; cnt[base] = 1;
int sum = 0;
for (int j = 1; j <= n; ++j) {
if (v[j] == i) {
cur += cnt[sum + base];
sum += 1;
} else {
sum -= 1;
cur -= cnt[sum + base];
}
ans += cur;
if (!cnt[sum + base]++) clr[++tot] = sum + base;
}
// std::cout << ans << "\n";
for (int j = 1; j <= tot; ++j)
cnt[clr[j]] = 0;
}
std::cout << ans << "\n";
}