ARC085F NRE

时间:2022-11-19 09:04:44

看了题解。

题目大意

你有一个长度为 \(N\) 的全为 $0$ 的序列 \(A\),给你一个长度同样为 \(N\) 的 $0/1$ 序列 \(B\),允许你对把 \(A\) 的一些区间中的数组全部改成 $1$,最小化 \(A\) 和 \(B\) 数字不同的位置个数。

解法

https://img.atcoder.jp/arc085/editorial.pdf

题解写得很清楚了。。。

总之就是把要求的东西进行一些奇妙变换,免去了变为 $1$ 的代价计算,把添加线段的那个没法优化的转移给换掉。。。

UPD:那个转换没有必要,直接 DP 即可。。。

实现

#include <bits/stdc++.h>

using namespace std;

const int INF = 2e9;

struct Node {
typedef Node* NP;
NP l, r;
int sz, mi;
Node(int _sz) : l(NULL), r(NULL), sz(_sz) {
mi = INF;
if (sz == 1) return;
l = new Node(sz/2);
r = new Node(sz-sz/2);
}
void set(int k, int v) {
if (sz == 1) {
mi = min(mi, v);
return;
}
if (k < sz/2) {
l->set(k, v);
} else {
r->set(k-sz/2, v);
}
mi = min(l->mi, r->mi);
}
int get(int a, int b) {
if (b <= 0 || sz <= a) return INF;
if (a <= 0 && sz <= b) return mi;
return min(l->get(a, b), r->get(a-sz/2, b-sz/2));
}
}; const int MN = 200010;
int n, q;
int b[MN];
vector<int> v[MN]; int main() {
cin.tie(0);
ios::sync_with_stdio(false); cin >> n;
int ans = 0;
for (int i = 0; i < n; i++) {
cin >> b[i];
if (b[i] == 0) {
ans++;
b[i]--;
}
}
cin >> q;
for (int i = 0; i < q; i++) {
int l, r;
cin >> l >> r; l--;
v[l].push_back(r);
}
Node* tr = new Node(n+1);
for (int i = 0; i <= n; i++) {
if (i) {
tr->set(i, tr->get(i-1, i) + b[i-1]);
} else {
tr->set(0, 0);
}
for (int j = 0; j < int(v[i].size()); j++) {
int r = v[i][j];
tr->set(r, tr->get(i, r));
}
}
ans += tr->get(n, n+1);
cout << ans << endl;
return 0;
}