洛谷 P13973 [VKOSHP 2024] Nightmare Sum
先用单调栈预处理出 i 位置左右第一个小于 a[i] 的位置,然后计算出 tot 数组 (tot[i]: 所有以 a[i] 为最小值的子数组总数) 和 pos 数组去记录每个数的位置所在 (每个数互不相同)。构造离线查询,对于固定的 i,枚举所有正整数 t 使得 t * a[i] <= maxA,把这个 t 对应的阈值 T = t * a[i] - 1 上记一条查询 “询问以 a[i] 为最小值且最大值 ≤ T 的子数组个数”。queries[T] 存的就是所有需要在阈值 T 下回答的索引 i,最后按 T 倒序维护值 > T 的位置集合并回答查询,然后容斥一下 tot[i] * t 减去这些子数组最大值不是 maxA 的数量就是最后答案。
#include <bits/stdc++.h>
// https://www.luogu.com.cn/problem/P13973
// from: cpp.json
#define INF 8e18
#define LD long double
#define i128 __int128_t
#define int long long
using namespace std;
void solve() {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int maxA = *max_element(a.begin(), a.end());
vector<int> L(n + 1), R(n + 1);
{
vector<int> stk;
for (int i = 1; i <= n; i++) {
while (!stk.empty() && a[stk.back()] > a[i]) {
stk.pop_back();
}
L[i] = stk.empty() ? 0 : stk.back();
stk.push_back(i);
}
}
{
vector<int> stk;
for (int i = n; i >= 1; i--) {
while (!stk.empty() && a[stk.back()] > a[i]) {
stk.pop_back();
}
R[i] = stk.empty() ? n + 1 : stk.back();
stk.push_back(i);
}
}
// 所有以 a[i] 为最小值的子数组总数
vector<int> tot(n + 1);
for (int i = 1; i <= n; i++) {
tot[i] = (i - L[i]) * (R[i] - i);
}
vector<int> pos(maxA + 1);
for (int i = 1; i <= n; i++) {
pos[a[i]] = i;
}
vector<vector<int>> queries(maxA);
for (int i = 1; i <= n; i++) {
int v = a[i];
int limit = maxA / v;
for (int t = 1; t <= limit; t++) {
int T = t * v - 1;
queries[T].push_back(i);
}
}
set<int> st;
int sum = 0;
for (int T = maxA - 1; T >= 0; T--) {
if (pos[T + 1] != 0) {
st.insert(pos[T + 1]);
}
for (auto idx : queries[T]) {
auto it = st.lower_bound(idx);
int r = (it == st.end() ? n + 1 : *it);
int l;
if (it == st.begin()) {
l = 0;
} else {
auto it2 = it;
it2--;
l = *it2;
}
int left = max(L[idx], l);
int right = min(R[idx], r);
if (left < idx && right > idx) {
int cnt = (idx - left) * (right - idx);
sum += cnt;
}
}
}
int ans = 0;
for (int i = 1; i <= n; i++) {
int t = maxA / a[i];
ans += tot[i] * t;
}
ans -= sum;
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
solve();
return 0;
}

浙公网安备 33010602011771号