AtCoder Beginner Contest 408
原题链接:AtCoder Beginner Contest 408
A
B
C
D
题意:一个01字符串,每次操作可以一个0变成1,或把1变成0,问将1集中到一起(也可以全是0)的最小次数。
思路:选一段区间,使得区间内0的数量加区间外1的数量和最小。转化为选定区间中0的个数减1的个数的最小值,再加上1的总数。复杂度 \(O(n)\)
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using u128 = unsigned __int128;
using i128 = __int128;
void solve() {
int N;
std::cin >> N;
std::string S;
std::cin >> S;
int cnt = std::count(S.begin(), S.end(), '1');
int ans = 0;
int suf = 0;
for (auto c : S) {
suf = std::min(0, suf) + (c == '1' ? -1 : 1);
ans = std::min(ans, suf);
}
ans += cnt;
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}
E
题意:带全图,1到n路径上权值or最小。
思路:
贪心从高位到枚举,缺少哪一位不连通该位一定为1。check感觉能用并查集。复杂度 \(O(n)\)
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using u128 = unsigned __int128;
using i128 = __int128;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N, M;
std::cin >> N >> M;
std::vector<std::vector<std::pair<int, int>>> adj(N);
for (int i = 0; i < M; i++) {
int u, v, w;
std::cin >> u >> v >> w;
u--;
v--;
adj[u].emplace_back(v, w);
adj[v].emplace_back(u, w);
}
std::vector<bool> vis(N);
std::queue<int> q;
auto check = [&](int s) {
std::fill(vis.begin(), vis.end(), false);
vis[0] = true;
q.push(0);
while (!q.empty()) {
int x = q.front();
q.pop();
for (auto [y, w] : adj[x]) {
if ((w & s) == w && !vis[y]) {
vis[y] = true;
q.push(y);
}
}
}
return vis[N - 1];
};
int ans = 0;
for (int d = 29; d >= 0; d--) {
if (!check(ans | ((1 << d) - 1))) {
ans |= 1 << d;
}
}
std::cout << ans << "\n";
return 0;
}
F
题意:1-n的排列,选一个开始,每次在R范围内下降高度大于D问最多能下降多少次
思路:高度从低到高遍历,seg维护高度-D时区间最大值,i是高度下标,每次找(i - R, i + R) 区间中的的最大值。
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using u128 = unsigned __int128;
using i128 = __int128;
template<class Info>
struct SegmentTree {
int n;
std::vector<Info> info;
SegmentTree() : n(0) {}
SegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
template<class T>
SegmentTree(std::vector<T> init_) {
init(init_);
}
void init(int n_, Info v_ = Info()) {
init(std::vector(n_, v_));
}
template<class T>
void init(std::vector<T> init_) {
n = init_.size();
info.assign(4 << std::__lg(n), Info());
std::function<void(int, int, int)> build = [&](int p, int l, int r) {
if (r - l == 1) {
info[p] = init_[l];
return;
}
int m = (l + r) / 2;
build(2 * p, l, m);
build(2 * p + 1, m, r);
pull(p);
};
build(1, 0, n);
}
void pull(int p) {
info[p] = info[2 * p] + info[2 * p + 1];
}
void modify(int p, int l, int r, int x, const Info &v) {
if (r - l == 1) {
info[p] = v;
return;
}
int m = (l + r) / 2;
if (x < m) {
modify(2 * p, l, m, x, v);
} else {
modify(2 * p + 1, m, r, x, v);
}
pull(p);
}
void modify(int p, const Info &v) {
modify(1, 0, n, p, v);
}
Info rangeQuery(int p, int l, int r, int x, int y) {
if (l >= y || r <= x) {
return Info();
}
if (l >= x && r <= y) {
return info[p];
}
int m = (l + r) / 2;
return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
}
Info rangeQuery(int l, int r) {
return rangeQuery(1, 0, n, l, r);
}
template<class F>
int findFirst(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y || r <= x) {
return -1;
}
if (l >= x && r <= y && !pred(info[p])) {
return -1;
}
if (r - l == 1) {
return l;
}
int m = (l + r) / 2;
int res = findFirst(2 * p, l, m, x, y, pred);
if (res == -1) {
res = findFirst(2 * p + 1, m, r, x, y, pred);
}
return res;
}
template<class F>
int findFirst(int l, int r, F &&pred) {
return findFirst(1, 0, n, l, r, pred);
}
template<class F>
int findLast(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y || r <= x) {
return -1;
}
if (l >= x && r <= y && !pred(info[p])) {
return -1;
}
if (r - l == 1) {
return l;
}
int m = (l + r) / 2;
int res = findLast(2 * p + 1, m, r, x, y, pred);
if (res == -1) {
res = findLast(2 * p, l, m, x, y, pred);
}
return res;
}
template<class F>
int findLast(int l, int r, F &&pred) {
return findLast(1, 0, n, l, r, pred);
}
};
struct Max {
int v = 0;
};
Max operator+(const Max &a, const Max &b) {
return {std::max(a.v, b.v)};
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N, D, R;
std::cin >> N >> D >> R;
std::vector<int> H(N), iH(N);
for (int i = 0; i < N; i++) {
std::cin >> H[i];
H[i]--;
iH[H[i]] = i;
}
SegmentTree<Max> seg(N);
std::vector<int> dp(N);
int ans = 0;
for (int i = 0; i < N; i++) {
int x = iH[i];
if (i >= D) {
seg.modify(iH[i - D], {dp[i - D]});
}
int res = 1 + seg.rangeQuery(std::max(0, x - R), std::min(N, x + 1 + R)).v;
dp[i] = res;
ans = std::max(ans, res);
}
std::cout << ans - 1 << "\n";
return 0;
}
G
题意:
给你满足 $ \frac AB < \frac CD$ 的正整数 \(A,B,C,D\) 。
求满足以下条件的最小正整数 \(q\) :
- 存在一个正整数 \(p\) ,使得 $ \frac AB <\frac pq < \frac CD$ .
思路:
#include <bits/stdc++.h>
using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using u128 = unsigned __int128;
using i128 = __int128;
std::vector<i64> get(i64 a, i64 b) {
std::vector<i64> v;
while (a % b) {
v.push_back(a / b);
a %= b;
std::swap(a, b);
}
v.push_back(a / b - 1);
return v;
}
std::mt19937 rng;
void solve() {
i64 A, B, C, D;
std::cin >> A >> B >> C >> D;
auto f = get(A, B);
auto g = get(C, D);
int l = std::max(f.size(), g.size()) + 2;
f.resize(l);
g.resize(l);
if (f > g) {
std::swap(f, g);
}
int i = 0;
while (f[i] == g[i]) {
i++;
}
if (*std::max_element(f.begin() + i + 1, f.end()) != 0) {
f.resize(i + 1);
} else if (f[i] + 1 < g[i]) {
f[i]++;
f.resize(i + 1);
} else if (*std::max_element(g.begin() + i + 2, g.end()) != 0) {
f[i]++;
f[i + 1] = g[i + 1];
f.resize(i + 2);
} else {
f[i]++;
f[i + 1] = g[i + 1] + 1;
f.resize(i + 2);
}
i64 p = 1, q = 1;
for (int i = f.size() - 1; i >= 0; i--) {
if (i % 2 == 1) {
q += p * f[i];
} else {
p += q * f[i];
}
}
std::cout << q << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int T;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号