π§© AtCoder Beginner Contest 381
π§© AtCoder Beginner Contest 381
# Info & Summary
- Date:
2024-11-22 - Completion Status: A β / B β / C β / D β / E β / F β / G β
- Problem Type:
| Problem | Type(s) | Data Structure / Algo | π₯ Key Insight / Mark |
|---|---|---|---|
| D | Constructive | Constructive | βπ₯ |
| E | Constructive | Binary Search | π§ π |
| F | Bitmask | Bitmask DP | ππ§ |
| G | Math | Math | π |
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 - 11/22 String

#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
string S;
cin >> N >> S;
if (N % 2 == 0)
{
cout << "No" << endl;
return 0;
}
for (int i = 0; i < N / 2; i++)
{
if (S[i] != '1')
{
cout << "No" << endl;
return 0;
}
}
for (int i = N / 2 + 1; i < N; i++)
{
if (S[i] != '2')
{
cout << "No" << endl;
return 0;
}
}
cout << (S[N / 2] == '/' ? "Yes" : "No") << endl;
return 0;
}π B - 1122 String

#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string S;
cin >> S;
if (S.size() % 2 == 1)
{
cout << "No" << endl;
return 0;
}
set<char> st;
for (int i = 0; i < S.size() - 1; i += 2)
{
if (S[i] != S[i + 1])
{
cout << "No" << endl;
return 0;
}
if (st.count(S[i]))
{
cout << "No" << endl;
return 0;
}
st.insert(S[i]);
}
cout << "Yes" << endl;
return 0;
}π C - 11/22 Substring

#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
string S;
cin >> N >> S;
vector<int> l1(N), r2(N);
for (int i = 0; i < N - 1; i++)
{
l1[i + 1] = S[i] == '1' ? 1 + l1[i] : 0;
}
for (int i = N - 1; i > 0; i--)
{
r2[i - 1] = S[i] == '2' ? 1 + r2[i] : 0;
}
int ans = 1;
for (int i = 0; i < N; i++)
{
if (S[i] == '/')
{
ans = max(ans, 1 + 2 * min(l1[i], r2[i]));
}
}
cout << ans << endl;
return 0;
}π D - 1122 Substring

Tips
Consider subarrays starting from the odd-indexed terms of A and the even-indexed terms separately
Tips
An important fact follows:
- For , if is a
1122sequence, then the sequence obtained by removing the last two elements, namely is also a1122sequence
Therefore, the problem can be solved with the Sliding Window trick
For an even number , let be the smallest odd number such that forms a 1122 sequence
- if , then is an empty sequence, especially a
1122sequence, so is always defined - for , we have:
- if
- otherwise
The sought value can be represented using as:
When we know , we can find as follows:
- if , then
- if , and if no element among equals , then
- if , and if there exists such that , then
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
vector<int> A(N);
for (int i = 0; i < N; i++)
{
cin >> A[i];
}
int ans = 0;
auto calc = [&](int l, int r)
{
// last[x] records the last index where value x was seen in a pair
vector<int> last(2e5 + 10, -2);
for (; (r + 1) < N; r += 2)
{
if (A[r] != A[r + 1])
{
l = r + 2;
}
else
{
l = max(l, last[A[r]] + 2);
}
ans = max(ans, r + 2 - l);
last[A[r]] = r;
}
};
// even-index start
calc(0, 0);
// odd-index start
calc(1, 1);
cout << ans << endl;
return 0;
}#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
vector<int> A(N);
for (int i = 0; i < N; i++)
{
cin >> A[i];
A[i]--;
}
int ans = 0;
for (int t = 0; t < 2; t++)
{
vector<bool> e(N);
for (int i = t, j = t; i < N; i += 2)
{
if (j < i)
{
j = i;
}
while (j + 1 < N && A[j + 1] == A[j] && !e[A[j]])
{
e[A[j]] = true;
j += 2;
}
if (i < j)
{
e[A[i]] = false;
}
ans = max(ans, j - i);
}
}
cout << ans << endl;
return 0;
}π E - 11/22 Subsequence

Tips
Let be the answer to some
- any
11/22string of length at most is contained in the substring from -th through -th characters ofSas a subsequence - no
11/22substring of length greater than is contained as a subsequence
Using this monotonicity, we can come up with the following binary search approach:
- Initially, let ,
- while , do the following:
- Let
- Check if an
11/22string of length exists as a subsequence within the segment - If it exists, let ; otherwise, let
- If the final , there is no
11/22string as a subsequence of the current segment. Otherwise, there exists an11/22string of length as a subsequence, which is the longest possible
But, we have not figure out how to solve the following subproblem:
Check if an
11/22string of length exists as a subsequence within the segment
Tips
This subproblem can be solved by doing an appropriate precalculation and referring to it appropriately
Specifically, precalculate the following sequences:
- : the monotonically increasing sequence consisting of indices with
- : the monotonically increasing sequence consisting of indices with
- : the monotonically increasing sequence consisting of indices with
Then the subproblem can be solved with an appropriate binary search in a total of time
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, Q;
string S;
cin >> N >> Q >> S;
vector<int> v1, v2, v3;
for (int i = 0; i < N; i++)
{
(S[i] == '1' ? v1 : S[i] == '2' ? v2
: v3)
.push_back(i);
}
while (Q--)
{
int L, R;
cin >> L >> R;
L--;
auto check = [&](int mid) -> bool
{
if (mid == 0)
{
// find '/'
auto it = lower_bound(v3.begin(), v3.end(), L);
return it != v3.end() && *it < R;
}
// find '1'
auto it1 = lower_bound(v1.begin(), v1.end(), L);
if (distance(it1, v1.end()) < mid)
{
return false;
}
int pos1_end = *(it1 + mid - 1);
// find '/'
auto it_slash = lower_bound(v3.begin(), v3.end(), pos1_end);
if (it_slash == v3.end())
{
return false;
}
int slash_pos = *it_slash;
// find '2'
auto it2 = lower_bound(v2.begin(), v2.end(), slash_pos);
if (distance(it2, v2.end()) < mid)
{
return false;
}
int pos2_end = *(it2 + mid - 1);
return pos2_end < R;
};
int l = -1, r = N + 1;
while (l + 1 < r)
{
int mid = l + (r - l) / 2;
if (check(mid))
{
l = mid;
}
else
{
r = mid;
}
}
cout << (l == -1 ? 0 : 2 * l + 1) << endl;
}
return 0;
}// Better version
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, Q;
string S;
cin >> N >> Q >> S;
vector<int> p1, p2;
for (int i = 0; i < N; i++)
{
if (S[i] == '1')
{
p1.push_back(i);
}
else if (S[i] == '2')
{
p2.push_back(i);
}
}
// prefix sum
vector<int> c1(N + 1), c2(N + 1), cs(N + 1);
for (int i = 0; i < N; i++)
{
c1[i + 1] = c1[i] + (S[i] == '1');
c2[i + 1] = c2[i] + (S[i] == '2');
cs[i + 1] = cs[i] + (S[i] == '/');
}
while (Q--)
{
int L, R;
cin >> L >> R;
L--;
// no '/' between (L, R)
if (cs[R] - cs[L] == 0)
{
cout << 0 << endl;
continue;
}
auto check = [&](int mid) -> bool
{
if (c1[R] - c1[L] < mid || c2[R] - c2[L] < mid)
{
return false;
}
int l = p1[c1[L] + mid - 1];
int r = p2[c2[R] - mid];
return l < r && cs[r] - cs[l] > 0;
};
int ans = 0;
int l = 1, r = N;
while (l <= r)
{
int mid = l + (r - l) / 2;
if (check(mid))
{
ans = mid;
l = mid + 1;
}
else
{
r = mid - 1;
}
}
// int ans = *std::ranges::partition_point(std::ranges::iota_view(1, N), [&](int x){
// if (c1[R] - c1[L] < x)
// {
// return false;
// }
// if (c2[R] - c2[L] < x)
// {
// return false;
// }
// int l = p1[c1[L] + x - 1];
// int r = p2[c2[R] - x];
// return l < r && cs[r] - cs[l] > 0;
// }) - 1;
ans = ans * 2 + 1;
cout << ans << endl;
}
return 0;
}π F - 1122 Subsequence

Tips
Note that the maximum possible subsequence of that is a 1122 sequence is , because
Thus, the solution can be built using Bitmask Dynamic Programming where each bit represents whether a specific number is included
Tips
Let's define:
dp[mask]: the minimum index such that a valid1122sequence ending before or at can be formed from the numbers inmask
Each bit in mask corresponds to an integer in the range
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
cin >> N;
vector<int> A(N);
for (int i = 0; i < N; i++)
{
cin >> A[i];
A[i]--;
}
// Determines the number of unique possible values in A,
// used for bitmask size 1 << M
int M = *max_element(A.begin(), A.end()) + 1;
// nxt[i][j] = first index >= j where value i appears in A
vector<vector<int>> nxt(M, vector<int>(N + 1));
for (int i = 0; i < M; i++)
{
nxt[i][N] = N;
for (int j = N - 1; j >= 0; j--)
{
nxt[i][j] = A[j] == i ? j : nxt[i][j + 1];
}
}
// dp[mask]: the minimum right endpoint you can reach
// using a valid 1122 sequence for the subset mask (bitmask)
vector<int> dp(1 << M, N + 1);
// Start with empty subset
dp[0] = 0;
int ans = 0;
for (int mask = 0; mask < (1 << M); mask++)
{
if (dp[mask] > N)
{
continue;
}
ans = max(ans, __builtin_popcount(mask) * 2);
// try to extend mask by adding a new number 'i'
for (int i = 0; i < M; i++)
{
// i is already in mask
if (mask >> i & 1)
{
continue;
}
// ns: new mask after adding 'i'
int ns = mask | 1 << i;
// Start searching from the position right after the end of the sequence for subset
int nj = dp[mask];
// Find the first occurrence of value i after position nj
nj = nxt[i][nj] + 1;
if (nj > N)
{
// If we can't find a valid first occurrence of i
continue;
}
// Find the second occurrence of value i after the first
nj = nxt[i][nj] + 1;
// Now, we have found two positions where value i occurs β
// satisfying the requirement to add i, i to the 1122 sequence
// Update the smallest position after inserting value i twice
dp[ns] = min(dp[ns], nj);
}
}
cout << ans << endl;
return 0;
}π G - Fibonacci Product

Warning
Hard Problems to Tackle Later
// TODO