Japan Registry Services (JPRS) Programming Contest 2025#1 (AtCoder Beginner Contest 392)
A - Shuffled Equation
点击查看代码
void solve() {
int a, b, c;
std::cin >> a >> b >> c;
if (a * b == c || a * c == b || b * c == a) {
std::cout << "Yes\n";
} else {
std::cout << "No\n";
}
}
B - Who is Missing?
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::set<int> s;
for (int i = 0; i < m; ++ i) {
int x;
std::cin >> x;
s.insert(x);
}
std::vector<int> ans;
for (int i = 1; i <= n; ++ i) {
if (!s.count(i)) {
ans.push_back(i);
}
}
std::cout << ans.size() << "\n";
for (auto & x : ans) {
std::cout << x << " \n"[x == ans.back()];
}
}
C - Bib
题意:第\(i\)个人编号为\(q_i\),指向\(p_i\)。求编号为\(i\)的人指向的人的编号。
编号为\(q_i\)的人指向人的编号为\(q_{p_i}\)。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> p(n), q(n);
for (int i = 0; i < n; ++ i) {
std::cin >> p[i];
-- p[i];
}
for (int i = 0; i < n; ++ i) {
std::cin >> q[i];
-- q[i];
}
std::vector<int> ans(n);
for (int i = 0; i < n; ++ i) {
ans[q[i]] = q[p[i]];
}
for (int i = 0; i < n; ++ i) {
std::cout << ans[i] + 1 << " \n"[i == n - 1];
}
}
D - Doubles
题意:有\(n\)个骰子,每个骰子有几率投出一些数,求两个骰子骰出相同数的最大概率。
\(n\)比较小,直接枚举两个骰子,然后计算它们可以骰出来的相同数的概率和。
点击查看代码
void solve() {
int n;
std::cin >> n;
const int N = 1e5 + 5;
std::vector<int> k(n);
std::vector<std::map<int, int> > cnt(n);
for (int i = 0; i < n; ++ i) {
std::cin >> k[i];
for (int j = 0; j < k[i]; ++ j) {
int x;
std::cin >> x;
++ cnt[i][x];
}
}
double ans = 0;
for (int i = 0; i < n; ++ i) {
for (int j = i + 1; j < n; ++ j) {
double sum = 0;
for (auto & [x, y] : cnt[i]) {
if (cnt[j].count(x)) {
sum += 1.0 * y / k[i] * cnt[j][x] / k[j];
}
}
ans = std::max(ans, sum);
}
}
std::cout << std::fixed << std::setprecision(12);
std::cout << ans << "\n";
}
E - Cables and Servers
题意:给你一个图,你可以改变某些边的连接端点使得整个图联通。
先求出每个联通块,然后每个联通块只需要\(size - 1\)条边,其中\(size\)是联通块的大小,那么其余的边是多余,可以用并查集求联通块和每个联通块多余的边。然后按顺序枚举所有联通块,记录前面联通块的可用边,和前面的联通块编号,每次先把前面联通块的边来连当前联通块,如果没有则用当前联通块的边尽可能连前面的联通块,模拟讨论一下就行,然后记得把没用过的边加进来,以及更新前面的联通块。
点击查看代码
struct DSU {
std::vector<int> fa, cnt;
DSU(int _n) {
init(_n);
}
void init(int _n) {
fa.assign(_n, 0);
cnt.assign(_n, 1);
std::iota(fa.begin(), fa.end(), 0);
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
bool merge(int x, int y) {
x = find(x), y = find(y);
if (x == y) {
return false;
}
fa[y] = x;
cnt[x] += cnt[y];
return true;
}
bool same(int x, int y) {
return find(x) == find(y);
}
int size(int x) {
return cnt[find(x)];
}
};
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::pair<int, int> > edges(m);
DSU d(n);
std::vector<int> id;
for (int i = 0; i < m; ++ i) {
int u, v;
std::cin >> u >> v;
-- u, -- v;
edges[i] = {u, v};
if (!d.merge(u, v)) {
id.push_back(i);
}
}
std::vector<std::vector<int>> g(n);
for (auto & i : id) {
g[d.find(edges[i].first)].push_back(i);
}
std::vector<std::array<int, 3>> ans;
std::vector<int> a, b;
for (int i = 0; i < n; ++ i) {
if (d.find(i) == i) {
if (a.size()) {
int j = a.back();
a.pop_back();
ans.push_back({j, edges[j].first, i});
d.merge(i, d.find(edges[j].first));
for (auto & j : g[i]) {
a.push_back(j);
}
} else if (g[i].size()) {
for (auto & j : g[i]) {
while (b.size() && d.same(b.back(), i)) {
b.pop_back();
}
if (!b.size()) {
a.push_back(j);
} else {
ans.push_back({j, edges[j].first, b.back()});
d.merge(b.back(), i);
b.pop_back();
}
}
b.push_back(i);
} else {
b.push_back(i);
}
}
}
std::cout << ans.size() << "\n";
for (auto & [x, y, z] : ans) {
std::cout << x + 1 << " " << y + 1 << " " << z + 1 << "\n";
}
}
F - Insert
题意:\(n\)个数依次加入序列,第\(i\)个放到第\(p_i\)个,那么第\(p_i\)到\(i-1\)位置上的数都要往后移。求最终序列。
考虑从后往前做,那么最后一个数的位置是可以确定的。假设当前以及放好了\(i + 1\)到\(n\),现在在放\(i\),那么\(i\)要一直被小于等于\(p_i\)的往后退,这个过程中同时\(p_i\)也要变大。那么如何求\(p_i\)最后的位置?考虑二分,如果\(p_i + sum(1, mid - 1) >= mid\)那么\(p_i\)的位置一定大于等于\(mid\),这是具有单调性的,因为\(p_i\)实际上是被一步一步推着往后移的。
点击查看代码
template <class T>
struct Fenwick {
int n;
std::vector<T> tr;
Fenwick(int _n) {
init(_n);
}
void init(int _n) {
n = _n;
tr.assign(_n + 1, {});
}
void add(int x, T v) {
for (int i = x; i <= n; i += i & -i) {
tr[i] += v;
}
}
T query(int x) {
T res = 0;
for (int i = x; i; i -= i & -i) {
res += tr[i];
}
return res;
}
T sum(int l, int r) {
return query(r) - query(l - 1);
}
};
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n + 1);
for (int i = 1; i <= n; ++ i) {
std::cin >> a[i];
}
Fenwick<int> tr(n);
std::vector<int> ans(n + 1);
for (int i = n; i >= 1; -- i) {
int l = a[i], r = n;
while (l < r) {
int mid = l + r + 1 >> 1;
if (a[i] + tr.query(mid - 1) >= mid) {
l = mid;
} else {
r = mid - 1;
}
}
int x = a[i] + tr.query(l - 1);
tr.add(x, 1);
ans[x] = i;
}
for (int i = 1; i <= n; ++ i) {
std::cout << ans[i] << " \n"[i == n];
}
}