Codeforces Round 1060 (Div. 2)
A. Notelock
题意:一个二进制串,问有多少位置的前\(k-1\)个位置没有\(1\)。
从前往后扫,维护一个可以包含的最右位置就行。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, k;
std::cin >> n >> k;
std::string s;
std::cin >> s;
int ans = 0;
for (int i = 0, j = 0; i < n; ++ i) {
if (i >= j && s[i] == '1') {
++ ans;
}
if (s[i] == '1') {
j = std::max(j, i + k);
}
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
B. Make it Zigzag
题意:一个数组,要求偶数位置大于左右两个位置。你可以做两个操作,一种是使得\(a_i\)等于前缀最大值,一种是使得\(a_i\)减一。求第二种操作的最小操作个数。
可以先把每个偶数位置做一次操作\(1\)。这样每个偶数位置已经达到最优了。然后遍历每个偶数位置让前后位置小于它即可。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
i64 ans = 0;
for (int i = 0, max = 0; i < n; ++ i) {
max = std::max(max, a[i]);
if (i & 1) {
a[i] = max;
}
}
for (int i = 1; i < n; i += 2) {
if (a[i - 1] >= a[i]) {
ans += a[i - 1] - (a[i] - 1);
}
if (i + 1 < n && a[i + 1] >= a[i]) {
ans += a[i + 1] - (a[i] - 1);
a[i + 1] = a[i] - 1;
}
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
C. No Cost Too Great
题意:两个长度为\(n\)的数组\(a, b\)。你每次可以使得\(a_i\)加一,花费\(b_i\)。求使得\(a\)中至少有两个元素的\(gcd\)大于\(1\)的最小花费。
先质数筛一下,然后求出每个数的质因子,如果有两个数有相同的质因子直接就\(ok\)。
否则看有没有偶数,如果有的话,那么就只有一个偶数,可以让奇数里花费最小的加一变成偶数。或者把这个偶数变成某个奇数的一个质因子的倍数,枚举质因子计算贡献即可。
如果没有偶数,那么可以拿花费最小的两个奇数加一。然后其它操作如果想小于这个操作,任意两个数的花费肯定大于等于这个花费,那么只有一个数操作一次或者两次的情况可能小于等于这个花费,那么枚举每个数加一次或者两次有没有质因子是其它数有的。最后最小花费的数可以操作多次,这个和前面的偶数情况一样计算贡献即可。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
std::vector<int> minp, primes;
void sieve(int n) {
minp.assign(n + 1, 0);
primes.clear();
for (int i = 2; i <= n; ++ i) {
if (minp[i] == 0) {
minp[i] = i;
primes.push_back(i);
}
for (auto p : primes) {
if (i * p > n) {
break;
}
minp[i * p] = p;
if (p == minp[i]) {
break;
}
}
}
}
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n), b(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int i = 0; i < n; ++ i) {
std::cin >> b[i];
}
std::map<int, int> cnt;
for (auto x : a) {
while (x > 1) {
int p = minp[x];
if (++ cnt[p] > 1) {
std::cout << 0 << "\n";
return;
}
while (x % p == 0) {
x /= p;
}
}
}
i64 ans = 0;
if (cnt.contains(2)) {
int pos = -1, minv = 2e9;
for (int i = 0; i < n; ++ i) {
if (a[i] % 2 == 0) {
pos = i;
} else {
minv = std::min(minv, b[i]);
}
}
ans = minv;
for (auto & [p, _] : cnt) {
if (a[pos] % p != 0) {
ans = std::min(ans, (i64)b[pos] * ((i64)(a[pos] + p - 1) / p * p - a[pos]));
}
}
} else {
std::vector<std::pair<int, int>> c;
for (int i = 0; i < n; ++ i) {
c.emplace_back(b[i], a[i]);
}
std::ranges::sort(c);
ans = c[0].first + c[1].first;
for (int i = 0; i < n; ++ i) {
int x = a[i] + 1;
if (b[i] >= ans) {
continue;
}
while (x > 1) {
int p = minp[x];
if (a[i] % p != 0 && cnt.contains(p)) {
ans = b[i];
break;
}
while (x % p == 0) {
x /= p;
}
}
}
for (int i = 0; i < n; ++ i) {
int x = a[i] + 2;
if (2 * b[i] >= ans) {
continue;
}
while (x > 1) {
int p = minp[x];
if (a[i] % p != 0 && cnt.contains(p)) {
ans = 2 * b[i];
break;
}
while (x % p == 0) {
x /= p;
}
}
}
int min = c[0].second, v = c[0].first;
for (auto & [p, _] : cnt) {
if (min % p != 0) {
ans = std::min(ans, (i64)v * ((i64)(min + p - 1) / p * p - min));
}
}
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
sieve(2e5 + 5);
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}
D. Catshock
题意:一棵树,一开始猫在\(1\)点,要去\(n\)点,有两个指令,第一个是让猫随机移动到当前点的一个邻点,一个是把\(u\)的邻边都断掉。给出不超过\(3n\)的指令,使得不管怎样猫最后停留在\(n\)点。第二个指令不能连续使用。
从\(1\)出发\(dfs\)一下,求出每个点到\(1\)的距离的奇偶性,和\(1\)到\(n\)路径上的点。
用两个大根堆分别存不在路径上的奇数距离和偶数距离的点,按照他们的距离排序。然后按时间奇偶性看,如果当前最大距离的奇偶性不是当前时间的奇偶性,那么猫一定不在当前最远的点上,则可以把这个点删掉,如此循环把所有非路径上的点删掉。
然后只剩下路径上的点,从头到尾一样操作即可。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<std::vector<int>> adj(n);
for (int i = 1; i < n; ++ i) {
int u, v;
std::cin >> u >> v;
-- u, -- v;
adj[u].push_back(v);
adj[v].push_back(u);
}
std::vector<int> path;
std::set<int> S;
std::vector<int> d(n);
auto dfs = [&](auto && self, int u, int fa) -> bool {
bool flag = false;
for (auto & v : adj[u]) {
if (v == fa) {
continue;
}
d[v] = d[u] + 1;
if (self(self, v, u)) {
flag = true;
}
}
if (u == n - 1 || flag) {
path.push_back(u);
S.insert(u);
return true;
}
return false;
};
dfs(dfs, 0, -1);
std::priority_queue<std::pair<int, int>> heap[2];
for (int i = 0; i < n; ++ i) {
if (!S.contains(i)) {
heap[d[i] & 1].emplace(d[i], i);
}
}
std::vector<std::pair<int, int>> ans;
int cnt = n - S.size();
int i = 0;
for (; cnt; ++ i) {
int x = i % 2 ^ 1;
if (heap[x].size()) {
if (heap[x ^ 1].size() && heap[x ^ 1].top().first > heap[x].top().first) {
} else {
int u = heap[x].top().second;
heap[x].pop();
ans.emplace_back(2, u);
-- cnt;
}
}
ans.emplace_back(1, -1);
}
std::ranges::reverse(path);
path.pop_back();
int f = 0;
for (auto & x : path) {
if (f) {
ans.emplace_back(1, -1);
f = 0;
++ i;
}
while (d[x] % 2 == i % 2) {
ans.emplace_back(1, -1);
++ i;
}
ans.emplace_back(2, x);
f = 1;
}
std::cout << ans.size() << "\n";
for (auto & [x, u] : ans) {
if (x == 1) {
std::cout << 1 << "\n";
} else {
std::cout << 2 << " " << u + 1 << "\n";
}
}
std::cout << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t -- ) {
solve();
}
return 0;
}

浙公网安备 33010602011771号