π§© 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
1122
sequence, then the sequence obtained by removing the last two elements, namely is also a1122
sequence
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
1122
sequence, 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/22
string of length at most is contained in the substring from -th through -th characters ofS
as a subsequence - no
11/22
substring 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/22
string of length exists as a subsequence within the segment - If it exists, let ; otherwise, let
- If the final , there is no
11/22
string as a subsequence of the current segment. Otherwise, there exists an11/22
string 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/22
string 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 valid1122
sequence 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