C. Not All Covered
差分
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<int> s(n+1);
rep(i, m) {
int l, r;
cin >> l >> r;
--l;
s[l]++; s[r]--;
}
rep(i, n) s[i+1] += s[i];
int ans = *min_element(s.begin(), s.begin()+n);
cout << ans << '\n';
return 0;
}
D. Flip to Gather
选择某个区间 \([l, r]\),将 \([l, r]\) 中所有 0 翻转成 1,将 \([l, r]\) 之外的 1 翻转成 \(0\),将二者的数量相加就是候选答案。但这个是 \(O(N^2)\)
比较简单的做法是 dp
对于选定的区间染上颜色 \(1\),区间左边染上颜色 \(0\),区间右边染上颜色 \(2\)
为了让区间左边都染上 \(0\),区间左边就要消耗翻转 1 的费用
为了让区间都染上 \(1\),区间就要消耗翻转 0 的费用
为了让区间右边都染上 \(2\),区间右边就要消耗翻转 1 的费用
记 dp[i][j] 表示到第 \(i\) 个位置位置末尾位置染上颜色 \(j\) 时的最小费用
时间复杂度为 \(O(N)\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
inline void chmin(int& a, int b) { if (a > b) a = b; }
void solve() {
int n;
string s;
cin >> n >> s;
const int INF = 1001001001;
vector dp(n+1, vector<int>(3, INF));
dp[0][0] = 0;
rep(i, n) {
rep(j, 3) {
int cost = (s[i]-'0') == (j%2) ? 0 : 1;
rep(pj, j+1) chmin(dp[i+1][j], dp[i][pj]+cost);
}
}
int ans = ranges::min(dp[n]);
cout << ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}
E. Minimum OR Path
按位考虑
为了使得答案最小,应该尽可能地让高位取到 \(0\)
所以应该从高位开始考虑
固定某一位 \(k\),对于每个边权 \(c\),如果答案在不考虑后 \(k\) 位得到的值覆盖 \(c\) 去掉后 \(k\) 位得到的值(也就是子集关系),那么就留下这条边,否则直接删掉,这样就得到了一张新图,然后判定新图上点 \(1\) 和 \(N\) 是否连通即可。如果连通,那么答案第 \(k\) 位上就可以取 \(0\)。可以用并查集来维护连通性。
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<tuple<int, int, int>> es;
rep(i, m) {
int a, b, c;
cin >> a >> b >> c;
--a; --b;
es.emplace_back(a, b, c);
}
int ans = 0;
for (int i = 29; i >= 0; --i) {
dsu uf(n);
for (auto [a, b, c] : es) {
if (((c>>i)|(ans>>i)) != (ans>>i)) continue;
uf.merge(a, b);
}
if (!uf.same(0, n-1)) ans |= 1<<i;
}
cout << ans << '\n';
return 0;
}
F. Athletic
记 dp[i] 表示从第 \(i\) 个脚踏架开始能移动的最大次数
然后用线段树加速一下即可
这个线段树要求支持单点加,区间 \(\max\)
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int op(int a, int b) { return max(a, b); }
int e() { return -1; }
int main() {
int n, D, R;
cin >> n >> D >> R;
vector<int> H(n);
rep(i, n) cin >> H[i], H[i]--;
vector<int> hi(n);
rep(i, n) hi[H[i]] = i;
vector<int> dp(n);
segtree<int, op, e> rmq(n);
rep(h, n) {
if (h >= D) {
int j = hi[h-D];
rmq.set(j, dp[j]);
}
int i = hi[h];
int l = max(0, i-R), r = min(n, i+R+1);
dp[i] = rmq.prod(l, r)+1;
}
int ans = ranges::max(dp);
cout << ans << '\n';
return 0;
}
G. A/B < p/q < C/D
\(\operatorname{Stern-Brocot}\) 树上二分
浙公网安备 33010602011771号