π§© AtCoder Beginner Contest 409
π§© AtCoder Beginner Contest 409
# Info & Summary
- Date:
2025-06-07
- Completion Status: A β / B β / C β / D β / E β / F β / G β
- Problem Type:
Problem | Type(s) | Data Structure / Algo | π₯ Key Insight / Mark |
---|---|---|---|
D | Math | Prefix Sum | π§ |
D | String | Constructive | π§ |
E | Tree DP | DFS / Tree DP | π§ π οΈ |
F | DSU | DSU | π |
G | Math | Fast Fourier Transform | π |
Details
Emoji | Label | Meaning |
---|---|---|
β | Important | Problem is strategically useful or has reusable patterns |
π₯ | Must master | Classic problem or technique that appears often and is worth mastering |
β οΈ | Reattempt | You attempted but failed; worth reviewing and solving again |
π§ | New to me | Introduced a new idea, technique, or pattern you hadnβt seen before |
π οΈ | Template | You built or improved a code template from solving this problem |
π | Too hard now | Beyond current ability to understand/solve; revisit after more practice |
π A - Conflict

#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
string T, A;
cin >> N >> T >> A;
for (int i = 0; i < N; i++)
{
if (T[i] == 'o' && A[i] == 'o')
{
cout << "Yes" << endl;
return 0;
}
}
cout << "No" << endl;
return 0;
}
π B - Citation

#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
vector<long long> A(N);
for (int i = 0; i < N; i++)
{
cin >> A[i];
}
int ans = 0;
for (int x = 0; x <= N; ++x)
{
int count = 0;
for (int i = 0; i < N; ++i)
{
if (A[i] >= x)
count++;
}
if (count >= x)
{
ans = x;
}
}
cout << ans << endl;
return 0;
}
π C - Equilateral Triangle

Tips
First, we will find the relative positions of point and point for each point
Let point 's coordinate be , and let coordinate denote the point units of distance away clockwise from coordinate
Point is units away clockwise from point , so its coordinate is:
By using cumulative sums, we can find in a total of time
Tips
Three points form a equilateral triangle
if and only if these three points divide the circumference equally. For example, if , this condition is represented as:
More formally, three points form a equilateral triangle
if and only if:
Therefore, for a frequency array cnt
of , the answer is:
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, L;
cin >> N >> L;
vector<int> d(N);
for (int i = 1; i < N; i++)
{
cin >> d[i];
d[i] = (d[i] + d[i - 1]) % L;
}
map<int, long long> cnt;
for (auto x : d)
{
cnt[x]++;
}
long long ans = 0;
if (L % 3 == 0)
{
for (int i = 0; i < L / 3; i++)
{
ans += (cnt[i] * cnt[i + L / 3] * cnt[i + L / 3 * 2]);
}
}
cout << ans << endl;
return 0;
}
π D - String Rotation

Tips
First, we decide the optimal :
- if , then the operation yields a string lexicographically smaller than
- if for all , then no operation makes lexicographically smaller
If any operation does, the earlier a character is made lexicographically smaller, the smaller the entire string becomes lexicographically, so it is optimal to set to the smallest with . If no such exists, picking is optimal, and the answer is itself
Next, we decide the optimal :
- It is better to repeatedly
defer
as long as the next character to is smaller than itself - Thus, the optimal is the smallest with , or is no such exists
Details
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--)
{
int N;
string S;
cin >> N >> S;
string ans = "";
char t = '.';
for (auto c : S)
{
if (ans.empty())
{
ans += c;
}
else if (c >= ans.back())
{
if (t < c && t != '#' && t != '.')
{
ans += t;
t = '#';
}
ans += c;
}
else
{
if (t == '.')
{
t = ans.back();
ans.pop_back();
// cout << t << endl;
ans += c;
}
else
{
if (t < c && t != '#')
{
ans += t;
t = '#';
}
// cout << t << ' ' << c << endl;
ans += c;
}
}
// cout << ans << endl;
}
if (t != '#' && t != '.')
{
ans += t;
}
cout << ans << endl;
}
return 0;
}
// Better version
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int N;
string S;
cin >> N >> S;
int i = 0;
while (i < N - 1 && S[i] <= S[i + 1])
{
i++;
}
int j = i;
while (j < N && S[j] <= S[i])
{
j++;
}
rotate(S.begin() + i, S.begin() + i + 1, S.begin() + j);
cout << S << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
π E - Pair Annihilation

Tips
Let us consider the contribution of edge to the answer. Without loss of generality, suppose that vertex is the parent of vertex
Let be the sum of over the vertices in the subtree rooted at vertex . No matter how you operate within this subtree, particles with remain. To annihilate these particles, we have to move them via edge to the outside of the subtree, or introduce particles from outside the subtree to pair with them. In any case, at least particles need to be moved along edge , which contributes by at least to the answer. Thus, the sought answer is at least:
In fact, there exists a procedure that achieves this lower bound:
We inspect the vertices from the leaves, and if the vertex still contains particles, move it toward the parent
Therefore, the optimal solution is . can be found with DFS
Details
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
vector<int> X(N);
for (int i = 0; i < N; i++)
{
cin >> X[i];
}
vector<vector<pair<int, int>>> adj(N);
for (int i = 0; i < N - 1; i++)
{
int u, v, w;
cin >> u >> v >> w;
u--;
v--;
adj[u].push_back({v, w});
adj[v].push_back({u, w});
}
long long ans = 0;
vector<bool> vis(N);
auto dfs = [&](auto &&self, int u) -> long long
{
vis[u] = true;
long long sum = X[u];
for (auto &[v, w] : adj[u])
{
if (!vis[v])
{
long long c = self(self, v);
ans += abs(c) * w;
sum += c;
}
}
return sum;
};
dfs(dfs, 0);
cout << ans << endl;
return 0;
}
// Better version
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
vector<int> X(N);
for (int i = 0; i < N; i++)
{
cin >> X[i];
}
vector<vector<pair<int, long long>>> adj(N);
for (int i = 0; i < N - 1; i++)
{
int u, v, w;
cin >> u >> v >> w;
u--;
v--;
adj[u].push_back({v, w});
adj[v].push_back({u, w});
}
long long ans = 0;
auto dfs = [&](auto &&self, int u, int p) -> void
{
for (auto &[v, w] : adj[u])
{
if (v == p)
{
continue;
}
self(self, v, u);
X[u] += X[v];
ans += w * abs(X[v]);
}
};
dfs(dfs, 0, -1);
cout << ans << endl;
return 0;
}
π F - Connecting Points

Tips
This problem can be made easier to solve by, instead of managing the set of pairs of vertices that are disconnected, the pairs that might
be disconnected
Prepare a priority queue pq
, so that we can retrieve a vertex pair with the minimum distance
Initially, put all vertex pairs to pq
Also, prepare a Disjoint Set Union (DSU)
of size so that we can determine the connectivity of vertices fast
Tips
For query 1
, add to pq
, where is the number of vertices in
For query 2
, perform the following operation while pq
is not empty:
- Pop with the
minimum
distance- do nothing if vertices and are connected
- otherwise, make and connected in
DSU
. Let . While the vertex pair with the minimum distance inpq
is equal to , pop that and make and connected in theDSU
. After this, print and determine the procedure. If nothing was printed by query2
, then has exactly one connected component, so print-1
For query 3
, determine if vertices and are connected using the DSU
The computational complexity is , where the bottle neck is inserting pairs of vertices to pq
#include <bits/stdc++.h>
using namespace std;
struct DSU
{
vector<int> f, siz;
DSU() {}
DSU(int n)
{
init(n);
}
void init(int n)
{
f.resize(n);
iota(f.begin(), f.end(), 0);
siz.assign(n, 1);
}
int find(int x)
{
while (x != f[x])
{
x = f[x] = f[f[x]];
}
return x;
}
bool same(int x, int y)
{
return find(x) == find(y);
}
bool merge(int x, int y)
{
x = find(x);
y = find(y);
if (x == y)
{
return false;
}
siz[x] += siz[y];
f[y] = x;
return true;
}
int size(int x)
{
return siz[find(x)];
}
};
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, Q;
cin >> N >> Q;
const int inf = 2e9 + 1;
vector<int> X(N), Y(N);
for (int i = 0; i < N; i++)
{
cin >> X[i] >> Y[i];
}
priority_queue<array<int, 3>, vector<array<int, 3>>, greater<>> pq;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < i; j++)
{
pq.push({abs(X[j] - X[i]) + abs(Y[j] - Y[i]), j, i});
}
}
DSU dsu(N + Q);
while (Q--)
{
int o;
cin >> o;
if (o == 1)
{
int nx, ny;
cin >> nx >> ny;
for (int i = 0; i < X.size(); i++)
{
pq.push({abs(X[i] - nx) + abs(Y[i] - ny), i, (int)X.size()});
}
X.push_back(nx);
Y.push_back(ny);
}
else if (o == 2)
{
int mind = inf;
while (!pq.empty())
{
auto [d, i, j] = pq.top();
if (d > mind)
{
break;
}
pq.pop();
if (dsu.same(i, j))
{
continue;
}
mind = d;
dsu.merge(i, j);
}
cout << (mind == inf ? -1 : mind) << endl;
}
else
{
int u, v;
cin >> u >> v;
u--;
v--;
cout << (dsu.same(u, v) ? "Yes" : "No") << endl;
}
}
return 0;
}
π G - Accumulation of Wealth

Warning
Hard Problems to Tackle Later
// TODO