VP Educational Codeforces Round 2
A. Extract Numbers
题意:一个字符串只包含数字小写字母和';', 以及','。由';'和','对字符串进行分隔。你要判断每个分隔的部分是不是合法数字,是就加入到第一个序列里,否则加入第二个序列。然后把两个序列按要求输出。
模拟题,就是把每段取出来判断就行了。不过要注意仅有一个空字符串的情况也不算序列为空。
点击查看代码
void solve() {
std::string s;
std::cin >> s;
int n = s.size();
std::vector<std::string> a, b;
for (int i = -1; i < n; ++ i) {
int j = i + 1;
bool flag = true;
std::string t;
while (j < n && s[j] != ';' && s[j] != ',') {
if (!isdigit(s[j])) {
flag = false;
}
t.push_back(s[j]);
++ j;
}
if (j == i + 1) {
b.push_back(",");
} else {
if (flag && (j == i + 2 || s[i + 1] != '0')) {
a.push_back(t + ",");
} else {
b.push_back(t + ",");
}
}
i = j - 1;
}
if (a.empty()) {
std::cout << "-\n";
} else {
a.back().pop_back();
std::cout << "\"";
for (auto & s : a) {
std::cout << s;
}
std::cout << "\"\n";
}
if (b.empty()) {
std::cout << "-\n";
} else {
b.back().pop_back();
std::cout << "\"";
for (auto & s : b) {
std::cout << s;
}
std::cout << "\"\n";
}
}
B. Queries about less or equal elements
题意:给你两个数组
将
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<int> a(n), b(m);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
for (int j = 0; j < m; ++ j) {
std::cin >> b[j];
}
std::sort(a.begin(), a.end());
for (int i = 0; i < m; ++ i) {
int res = std::upper_bound(a.begin(), a.end(), b[i]) - a.begin() + 1;
-- res;
std::cout << res << " \n"[i == m - 1];
}
}
C. Make Palindrome
题意:给你一个字符串,你可以更改任意位置的字符,然后可以重新排序,使得字符串是回文串,求最小操作数的字典序最小的方案。
要操作数最小,那么肯定优先让每个字符和相同的两两匹配,那么每个种类的字符最多有一个匹配不上。
对于这些匹配不上的字符,因为答案要字典序最小,那么就让最大的变成最小的。
点击查看代码
void solve() {
std::string s;
std::cin >> s;
std::vector<int> cnt(26);
for (auto & c : s) {
++ cnt[c - 'a'];
}
for (int l = 0, r = 25; l < r;) {
while (l < r && cnt[l] % 2 == 0) {
++ l;
}
while (l < r && cnt[r] % 2 == 0) {
-- r;
}
if (l < r) {
cnt[l] += 1;
cnt[r] -= 1;
}
}
std::string ans;
for (int i = 0; i < 26; ++ i) {
int n = cnt[i] / 2;
ans += std::string(n, i + 'a');
}
std::cout << ans;
for (int i = 0; i < 26; ++ i) {
if (cnt[i] % 2) {
std::cout << (char)(i + 'a');
break;
}
}
std::reverse(ans.begin(), ans.end());
std::cout << ans << "\n";
}
D. Area of Two Circles' Intersection
题意:求两个圆的面积交。
纯数学题,也是模板题。但我数学太差,只能看别人题解。
首先讨论两个圆是相交还是相离还是包含,如果相离则答案为0,如果包含则是小圆的面积。现在考虑相交的情况。
发现其交集是两个弓形的面积和,而每个弓形可以单独求,它就是对于圆里的一个扇形面积减去一个三角形面积。
那么可以根据余弦定理求出扇形的夹角,就可以计算这个弓形的面积了。
这题需要开long double
点击查看代码
#define double long double
void solve() {
double x1, y1, r1, x2, y2, r2;
std::cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
double dx = x1 - x2, dy = y1 - y2;
double d = std::sqrt(dx * dx + dy * dy);
std::cout << std::fixed << std::setprecision(12);
double ans = 0;
if (d >= r1 + r2) {
std::cout << ans << "\n";
return;
}
if (d <= std::fabs(r1 - r2)) {
std::cout << std::min(r1, r2) * std::min(r1, r2) * std::acos(-1) << "\n";
return;
}
double angle1 = 2 * std::acos((r1 * r1 + d * d - r2 * r2) / (2 * r1 * d));
double angle2 = 2 * std::acos((r2 * r2 + d * d - r1 * r1) / (2 * r2 * d));
ans = r1 * r1 * (angle1 - std::sin(angle1)) / 2 + r2 * r2 * (angle2 - std::sin(angle2)) / 2;
std::cout << ans << "\n";
}
E. Lomsat gelral
题意:给你一棵树,每个数有颜色,求每个子树颜色数最多的颜色编号之和。
解法一:
线段树合并还是老早前学的,并且一直没用过,今天碰上没想到还能写出来。
每个点动态开点建线段树,然后把每棵子树合并起来。
点击查看代码
#define ls(u) (tr[u].lson)
#define rs(u) (tr[u].rson)
const int N = 1e5 + 5;
struct Node {
int lson, rson;
i64 max, sum;
}tr[N << 5];
int tot = 0;
void pushup(int u) {
tr[u].max = std::max(tr[ls(u)].max, tr[rs(u)].max);
tr[u].sum = 0;
if (tr[ls(u)].max == tr[u].max) {
tr[u].sum += tr[ls(u)].sum;
}
if (tr[rs(u)].max == tr[u].max) {
tr[u].sum += tr[rs(u)].sum;
}
}
void modify(int & u, int l, int r, int p, int add) {
if (u == 0) {
u = ++ tot;
}
if (l == r) {
tr[u].max += add;
tr[u].sum = l;
return;
}
int mid = l + r >> 1;
if (p <= mid) {
modify(ls(u), l, mid, p, add);
} else {
modify(rs(u), mid + 1, r, p, add);
}
pushup(u);
}
void merge(int & u, int v, int l, int r) {
if (v == 0) {
return;
}
if (u == 0) {
u = ++ tot;
tr[u] = tr[v];
return;
}
if (l == r) {
tr[u].max += tr[v].max;
return;
}
int mid = l + r >> 1;
merge(ls(u), ls(v), l, mid);
merge(rs(u), rs(v), mid + 1, r);
pushup(u);
}
void solve() {
int n;
std::cin >> n;
std::vector<int> c(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> c[i];
}
std::vector<std::vector<int>> adj(n + 1);
for (int i = 1; i < n; ++ i) {
int u, v;
std::cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
std::vector<int> root(n + 1);
std::vector<i64> ans(n + 1);
auto dfs = [&](auto self, int u, int fa) -> void {
for (auto & v : adj[u]) {
if (v == fa) {
continue;
}
self(self, v, u);
merge(root[u], root[v], 1, n);
}
modify(root[u], 1, n, c[u], 1);
ans[u] = tr[root[u]].sum;
};
dfs(dfs, 1, 0);
for (int i = 1; i <= n; ++ i) {
std::cout << ans[i] << " \n"[i == n];
}
}
解法二:
之前没学过
关于时间复杂度,是
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> c(n);
for (int i = 0; i < n; ++ i) {
std::cin >> c[i];
}
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> size(n), son(n, -1);
auto dfs = [&](auto self, int u, int fa) -> void {
size[u] = 1;
for (auto & v : adj[u]) {
if (v == fa) {
continue;
}
self(self, v, u);
size[u] += size[v];
if (son[u] == -1 || size[v] > size[son[u]]) {
son[u] = v;
}
}
};
std::vector<int> cnt(n + 1);
i64 sum = 0, max = 0;
int Son = -1;
auto add = [&](auto self, int u, int fa, int val) -> void {
cnt[c[u]] += val;
if (cnt[c[u]] > max) {
max = cnt[c[u]];
sum = c[u];
} else if (cnt[c[u]] == max) {
sum += c[u];
}
for (auto & v : adj[u]) {
if (v == fa || v == Son) {
continue;
}
self(self, v, u, val);
}
};
std::vector<i64> ans(n);
auto dfs1 = [&](auto self, int u, int fa, int flag) -> void {
for (auto & v : adj[u]) {
if (v == fa) {
continue;
}
if (v != son[u]) {
self(self, v, u, 0);
}
}
if (son[u] != -1) {
self(self, son[u], u, 1);
}
Son = son[u];
add(add, u, fa, 1);
Son = -1;
ans[u] = sum;
if (!flag) {
add(add, u, fa, -1);
sum = 0, max = 0;
}
};
dfs(dfs, 0, -1);
dfs1(dfs1, 0, -1, 1);
for (int i = 0; i < n; ++ i) {
std::cout << ans[i] << " \n"[i == n - 1];
}
}
F. Edge coloring of bipartite graph
题意:对二分图的边进行染色,使得没有相邻边颜色相同并且要求颜色最少,求方案。
看起来就很典的题,但我以前却没遇到过。
结论是最少颜色数等于点的最大度数。
首先显然答案大于等于最大度数,因为一个点相连的边都互相相邻。
那么我们怎么证明可以等于呢,参考别人的题解是构造法,并且我们可以按照这个方法求方案。
我们按顺序给边染色,现在考虑对
如果
否则我们发现不管对
点击查看代码
void solve() {
int a, b, m;
std::cin >> a >> b >> m;
int n = a + b;
std::vector<std::pair<int, int>> edges(m);
std::vector<int> in(n);
for (int i = 0; i < m; ++ i) {
int u, v;
std::cin >> u >> v;
v += a;
-- u, -- v;
++ in[u]; ++ in[v];
edges[i] = {u, v};
}
std::vector f(n, std::vector<int>(n, -1));
for (int i = 0; i < m; ++ i) {
auto & [u, v] = edges[i];
int c1 = 0, c2 = 0;
while (f[u][c1] != -1) {
++ c1;
}
while (f[v][c2] != -1) {
++ c2;
}
f[u][c1] = v;
f[v][c2] = u;
if (c1 == c2) {
continue;
}
for (int i = c2, k = v; ~k; k = f[k][i], i = i ^ c1 ^ c2) {
std::swap(f[k][c1], f[k][c2]);
}
}
int ans = 0;
for (int i = 0; i < n; ++ i) {
ans = std::max(ans, in[i]);
}
std::cout << ans << "\n";
for (int i = 0; i < m; ++ i) {
auto & [u, v] = edges[i];
for (int j = 0; j < n; ++ j) {
if (f[u][j] == v) {
std::cout << j + 1 << " \n"[i == m - 1];
break;
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具