π§© AtCoder Beginner Contest 390
π§© AtCoder Beginner Contest 390
# Info & Summary
- Date:
2025-01-25
- Completion Status: A β / B β / C β / D β / E β / F β / G β
- Problem Type:
Problem | Type(s) | Data Structure / Algo | π₯ Key Insight / Mark |
---|---|---|---|
D | Bell Number | DFS/Bell Number | βπ₯π§ |
E | DP | DP/Binary Search | π₯ |
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 - 12435

#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
vector<int> A(5);
for (int i = 0; i < 5; i++)
{
cin >> A[i];
}
vector<int> ans = {1, 2, 3, 4, 5};
for (int i = 0; i < 4; i++)
{
vector<int> B = A;
swap(B[i], B[i + 1]);
if (B == ans)
{
cout << "Yes" << endl;
return 0;
}
}
cout << "No" << endl;
return 0;
}
π B - Geometric Sequence

#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];
}
for (int i = 1; i < n - 1; i++)
{
if (A[i - 1] * A[i + 1] != A[i] * A[i])
{
cout << "No" << endl;
return 0;
}
}
cout << "Yes" << endl;
return 0;
}
π C - Paint to make a rectangle

#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int h, w;
cin >> h >> w;
vector<string> grid(h);
int minx = h, miny = w;
int maxx = 0, maxy = 0;
for (int i = 0; i < h; i++)
{
cin >> grid[i];
for (int j = 0; j < w; j++)
{
if (grid[i][j] == '#')
{
minx = min(minx, i);
miny = min(miny, j);
maxx = max(maxx, i);
maxy = max(maxy, j);
}
}
}
for (int i = minx; i <= maxx; i++)
{
for (int j = miny; j <= maxy; j++)
{
if (grid[i][j] == '.')
{
cout << "No" << endl;
return 0;
}
}
}
cout << "Yes" << endl;
return 0;
}
π D - Stone XOR

Tips
Considering which bagsβ stones merge into one in the final state, we find that the answer to the problem is equal to that to the following:
consider dividing bags , bags , ..., and bags into several groups, and finding the total number of stones in the bags in each group. How many distinct integers can be the XOR (exclusive logical sum) of the counts?
Tips
The number of ways to divide items into groups (where the items and groups are indistinguishable) is known as the Bell number . The Bell number increases as increases, and for , so we can exhaustively enumerate them under the constraints () of this problem
There are several ways for the exhaustive search; one is a DFS (Depth-First Search) based approach as follows. Starting from the state with depth and groups, we perform the following operation:
Tips
When the current depth and there are groups, perform the following operation for each in order:
- Let bag belong to group
- Here, if , it means we create a new group consisting only of bag
- If , record the
XOR
of the (group-wise) total numbers of stones in each group - IF , advance to the nex depth
- Note that the number of groups has increased if
After searching for all , go back to the previous depth . If , stop the search
After the search ends, the sought answer is the number of distinct recorded integers
#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];
}
// keep track of the number of stones in each group at each step
vector<long long> cnt(n, 0);
// A set to store distinct XOR results
unordered_set<long long> st;
// The current XOR value
long long val = 0;
// idx: The current index of the bag being considered
// sz: The number of groups formed so far
auto dfs = [&](auto &&self, int idx, int sz) -> void
{
// For each group, we recursively decide whether to add the current bag to an existing group or create a new group
for (int i = 0; i <= sz; i++)
{
val ^= cnt[i]; // XOR out the current value of the group
cnt[i] += A[idx]; // Add the current bag to the group
val ^= cnt[i]; // XOR in the new value of the group
if (idx == n - 1)
{
// If it's the last bag, insert the XOR result into the set
st.insert(val);
}
else if (i < sz)
{
// If we're not adding a new group, continue exploring
self(self, idx + 1, sz);
}
else
{
// Otherwise, create a new group
self(self, idx + 1, sz + 1);
}
val ^= cnt[i]; // Backtrack: XOR out the current value of the group
cnt[i] -= A[idx]; // Remove the current bag from the group
val ^= cnt[i]; // XOR in the old value
}
};
// start with the first bag and an empty set of groups
dfs(dfs, 0, 0);
cout << (int)st.size() << endl;
return 0;
}
π E - Vitamin Balance

Tips
For each vitamin (), precalcaulte the maximum intake of vitamin (ignoring the other vitamin) to that the total calorie consumption does not exceed (), using Dynamic Programming
Let represent the maximum intake of vitamin when choosing foods from the -st through -th, so that the total calorie consumption is exactly
(or if it is impossible):
- First, we have and , where
- Next, for each food
- if food () does not contain vitamin , then
- if it does, considering whether to eat or not:
where , for , we have
- The sought value is the resulting
Next, we consider , the maximum intake of vitamin so that the total calorie consumption does not exceed (, which satisfies . This can be computed incrementally as ans )
Finally, when the total calorie consumption of the food to intake vitamin () is , the minimum intake among vitamin , and is given as , so the sought value is:
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, x;
cin >> n >> x;
vector<vector<pair<int, int>>> food(3);
for (int i = 0; i < n; i++)
{
int v, a, c;
cin >> v >> a >> c;
v--;
food[v].push_back({a, c});
}
auto solve = [&](vector<pair<int, int>> ac) -> vector<int>
{
vector<int> dp(x + 1);
for (auto [a, c] : ac)
{
for (int i = x; i >= c; i--)
{
dp[i] = max(dp[i], dp[i - c] + a);
}
}
return dp;
};
auto f = solve(food[0]);
auto g = solve(food[1]);
auto h = solve(food[2]);
int ans = 0;
for (int i = 0; i <= x; i++)
{
for (int j = 0; i + j <= x; j++)
{
ans = max(ans, min({f[i], g[j], h[x - i - j]}));
}
}
cout << ans << endl;
return 0;
}
Binary Search
The goal is to find the largest satisfaction value mid
such that the total number of items selected across all categories does not exceed the budget
Details
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, x;
cin >> n >> x;
vector<vector<pair<int, int>>> food(3);
for (int i = 0; i < n; i++)
{
int v, a, c;
cin >> v >> a >> c;
v--;
food[v].push_back({a, c});
}
auto solve = [&](vector<pair<int, int>> ac) -> vector<int>
{
vector<int> dp(x + 1);
for (auto [a, c] : ac)
{
for (int i = x; i >= c; i--)
{
dp[i] = max(dp[i], dp[i - c] + a);
}
}
return dp;
};
auto f = solve(food[0]);
auto g = solve(food[1]);
auto h = solve(food[2]);
auto check = [&](long long mid) -> bool
{
long long sum = 0;
sum += lower_bound(f.begin(), f.end(), mid) - f.begin();
sum += lower_bound(g.begin(), g.end(), mid) - g.begin();
sum += lower_bound(h.begin(), h.end(), mid) - h.begin();
return sum <= x;
};
long long l = 0, r = 1e10;
while (r - l > 1)
{
long long mid = l + (r - l) / 2;
if (check(mid))
{
l = mid;
} else {
r = mid;
}
}
cout << l << endl;
return 0;
}
π F - Double Sum 3

Warning
Hard Problems to Tackle Later
Tips
When the blackboard has some integers, it is optimal to pick and to maximize in order to minimize the number of operations
That is, we can pick such that:
- is not written on the blackboard
- all integers from through are written on the blackboard, and
- is not written on the blackboard
and remove them
// TODO
π G - Permutation Concatenation

Warning
Hard Problems to Tackle Later
// TODO