Codeforces Round 1043 (Div. 3)
A. Homework
按题意模拟。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, m;
std::string a, b, c;
std::cin >> n >> a >> m >> b >> c;
int l = 0, r = m - 1;
for (int i = 0; i < m; ++ i) {
if (c[i] == 'V') {
a = b[i] + a;
} else {
a = a + b[i];
}
}
std::cout << a << "\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. The Secret Number
题意:一个数\(x\)在某尾添加了若干个\(0\)后变成\(y\),给出\(n = x + y\)。求所有合法的\(x\)。
\(n\)显然等于\((10^k + 1)x\)。
枚举即可。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
i64 n;
std::cin >> n;
std::vector<i64> ans;
for (__int128 i = 10; i < n; i *= 10) {
if (n % (i + 1) == 0) {
ans.push_back(n / (i + 1));
}
}
std::ranges::sort(ans);
std::cout << ans.size() << "\n";
for (auto & x : ans) {
std::cout << x << " \n"[x == ans.back()];
}
}
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;
}
C1. The Cunning Seller (easy version)
题意:第\(i\)个物品体积为\(3^i\),代价为\(3^{i+1} + i3^{i-1}\), 每个物品有无限个。求恰好装满容量为\(n\)的背包的方案中,选择最少的物品的方案里代价最小的。
因为要选择最少的物品,那么肯定是按体积从大到小选。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
i64 n;
std::cin >> n;
std::vector<std::pair<i64, i64>> a;
std::vector<i64> p3;
for (i64 x = 1; x <= 1e10; x *= 3) {
p3.push_back(x);
}
for (int i = 0; i + 1 < p3.size(); ++ i) {
a.emplace_back(p3[i], p3[i + 1] + i * (i ? p3[i - 1] : 1));
}
i64 ans = 0;
for (int i = (int)a.size() - 1; i >= 0; -- i) {
i64 cnt = n / a[i].first;
ans += cnt * a[i].second;
n %= a[i].first;
}
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;
}
C2. The Cunning Seller (hard version)
题意:和\(C1\)的区别是,最多选择\(k\)个物品使得体积为\(n\)的最小代价。
发现可以用三个\(i-1\)物品代替一个\(i\)物品。那么先从大到小拿,记录每个物品拿的个数,然后从大到小能换小的就换小的,每次会使得选择的物品增加\(2\)(去掉一个\(i\)添加\(3\)个\(i-1\))。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
i64 n, k;
std::cin >> n >> k;
std::vector<std::pair<i64, i64>> a;
std::vector<i64> p3;
for (i64 x = 1; x <= 1e10; x *= 3) {
p3.push_back(x);
}
for (int i = 0; i + 1 < p3.size(); ++ i) {
a.emplace_back(p3[i], p3[i + 1] + i * (i ? p3[i - 1] : 1));
}
int m = a.size();
std::vector<i64> cnt(m);
for (int i = m - 1; i >= 0; -- i) {
cnt[i] = n / a[i].first;
n %= a[i].first;
k -= cnt[i];
}
if (k < 0) {
std::cout << -1 << "\n";
return;
}
for (int i = m - 1; i > 0; -- i) {
i64 t = std::min(k / 2, cnt[i]);
cnt[i] -= t;
cnt[i - 1] += t * 3;
k -= t * 2;
}
i64 ans = 0;
for (int i = 0; i < m; ++ i) {
ans += a[i].second * cnt[i];
}
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;
}
D. From 1 to Infinity
题意:所有正整数从小到大排列组成一个字符串,截取其前\(k\)个数字,求每一位数字的和。
可以先枚举数字长度,那么长度为\(i\)的数字有\(10^{i+1} - 10^i - 1\)个,如果\(\lfloor \frac{k}{i} \rfloor\)大于这个数,那么长度为\(i\)的数都被包含,\(k\)减少\((10^{i+1} - 10^i - 1)\times i\)。如果小于等于这个数,则可以得到最后一个数了,这个数可能不完整,可以先加上它的贡献。
然后考虑求\([1, n]\)的数位和。可以数位\(dp\)。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
i64 k;
std::cin >> k;
i64 ans = 0, n;
for (i64 x = 1, i = 1; ; x *= 10, ++ i) {
i64 l = x, r = x * 10 - 1;
if (k / i > r - l + 1) {
k -= (r - l + 1) * i;
} else {
i64 t = k / i;
k -= t * i;
if (k) {
std::string s = std::to_string(l + t);
for (int i = 0; i < k; ++ i) {
ans += s[i] - '0';
}
}
n = l + t - 1;
break;
}
}
auto get = [&](i64 n) -> i64 {
std::vector<int> a;
while (n) {
a.push_back(n % 10);
n /= 10;
}
int m = a.size();
std::vector<i64> f(m, -1), g(m, -1);
auto dp = [&](auto & self, int u, bool limit, bool zero) -> std::pair<i64, i64> {
if (u == -1) {
return {0, 1};
}
if (!limit && !zero && f[u] != -1) {
return {f[u], g[u]};
}
int up = limit ? a[u] : 9;
i64 res = 0, cnt = 0;
for (int i = 0; i <= up; ++ i) {
auto [x, y] = self(self, u - 1, limit && i == up, zero && i == 0);
res += x + i * y;
cnt += y;
}
if (!limit && !zero) {
f[u] = res;
g[u] = cnt;
}
return {res, cnt};
};
return dp(dp, m - 1, true, true).first;
};
ans += get(n);
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;
}
E. Arithmetics Competition
题意:两个数字\(a, b\)。每次查询给出\(x, y, z\)。\(a\)中最多拿出\(x\)个数,\(b\)中最多拿出\(y\)个数,两个数字拿出恰好\(z\)个数。求这些数的和最大是多少。
如果没有\(x, y\)的限制,考虑拿\(z\)个数的最大和,肯定是先把两个数组都从大到小排序,那么这是一个归并两个数字过程,每次拿两个数组开头最大的那一个。那么可以求得拿\(z\)个数是从\(a\)里拿\(X_z\)个数,从\(b\)里拿\(Y_z\)个数。那么对于每个询问,如果\(x \geq X_z\)且\(y \geq Y_z\)则直接就是最大值。否则肯定是一个数组拿的数变少了,假设是\(a\),那么多出来的数从\(b\)里拿就行,因为\(a\)肯定就是拿这些数了,不会再减少了。那么预处理前缀和就可以\(O(1)\)回答。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, m, q;
std::cin >> n >> m >> q;
std::vector<int> a(n), b(m);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int i = 0; i < m; ++ i) {
std::cin >> b[i];
}
std::ranges::sort(a, std::greater<>());
std::ranges::sort(b, std::greater<>());
std::vector<i64> suma(n + 1), sumb(m + 1);
for (int i = 0; i < n; ++ i) {
suma[i + 1] = suma[i] + a[i];
}
for (int i = 0; i < m; ++ i) {
sumb[i + 1] = sumb[i] + b[i];
}
std::vector<int> A(n + m + 1), B(n + m + 1);
for (int i = 0, j = 0, k = 1; k <= n + m; ++ k) {
if (j == m || (i < n && a[i] >= b[j])) {
++ i;
} else {
++ j;
}
A[k] = i;
B[k] = j;
}
while (q -- ) {
int x, y, z;
std::cin >> x >> y >> z;
if (x >= A[z] && y >= B[z]) {
std::cout << suma[A[z]] + sumb[B[z]] << "\n";
} else if (x < A[z]) {
std::cout << suma[x] + sumb[B[z] + A[z] - x] << "\n";
} else {
std::cout << suma[A[z] + B[z] - y] + sumb[y] << "\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;
}
F. Rada and the Chamomile Valley
题意:一个简单无向图,每次问一个点距离最近的关键边里编号最小的。关键边是指\(1\)到\(n\)的任意一条路径都会经过的边。
考虑如何求出关键边,缩点就行了。此时图变成了树,\(1\)和\(n\)所在联通分量的路径是唯一的。
然后以距离为第一关键字,答案编号为第二关键字跑\(dijkstra\)。
查询直接\(O(1)\)回答就行了。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::vector<std::pair<int, int>>> adj(n);
std::vector<std::pair<int, int>> edges(m);
for (int i = 0; i < m; ++ i) {
int u, v;
std::cin >> u >> v;
-- u, -- v;
adj[u].emplace_back(v, i);
adj[v].emplace_back(u, i);
edges[i] = {u, v};
}
std::vector<int> dfn(n, -1), low(n), bel(n), stk(n);
int idx = 0, cnt = 0;
auto tarjan = [&](auto & self, int u, int fa) -> void {
dfn[u] = low[u] = idx ++ ;
stk.push_back(u);
for (auto & [v, id] : adj[u]) {
if (id == fa) {
continue;
}
if (dfn[v] == -1) {
self(self, v, id);
low[u] = std::min(low[u], low[v]);
} else {
low[u] = std::min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]) {
int v;
do {
v = stk.back();
stk.pop_back();
bel[v] = cnt;
} while (v != u);
++ cnt;
}
};
tarjan(tarjan, 0, -1);
std::vector<std::vector<std::pair<int, int>>> adj1(cnt);
for (int i = 0; i < m; ++ i) {
auto & [u, v] = edges[i];
if (bel[u] != bel[v]) {
adj1[bel[u]].emplace_back(bel[v], i);
adj1[bel[v]].emplace_back(bel[u], i);
}
}
std::set<int> S;
auto dfs = [&](auto & self, int u, int fa) -> bool {
if (u == bel[n - 1]) {
return true;
}
for (auto & [v, id] : adj1[u]) {
if (v == fa) {
continue;
}
if (self(self, v, u)) {
S.insert(id);
return true;
}
}
return false;
};
dfs(dfs, bel[0], -1);
using A = std::tuple<int, int, int>;
std::priority_queue<A, std::vector<A>, std::greater<A>> heap;
std::vector<int> dist(n, 1e9), ans(n, -1);
for (auto & id : S) {
auto & [u, v] = edges[id];
if (ans[u] == -1) {
heap.emplace(0, id + 1, u);
ans[u] = id + 1;
dist[u] = 0;
}
if (ans[v] == -1) {
heap.emplace(0, id + 1, v);
ans[v] = id + 1;
dist[v] = 0;
}
}
while (heap.size()) {
auto [d, id, u] = heap.top(); heap.pop();
if (dist[u] != d) {
continue;
}
for (auto & [v, _] : adj[u]) {
if (dist[v] > dist[u] + 1 || (dist[v] == dist[u] + 1 && ans[u] < ans[v])) {
dist[v] = dist[u] + 1;
ans[v] = ans[u];
heap.emplace(dist[v], ans[v], v);
}
}
}
int Q;
std::cin >> Q;
while (Q -- ) {
int c;
std::cin >> c;
-- c;
std::cout << ans[c] << " \n"[!Q];
}
}
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号