A. Attach 00
因为 \(100K\) 满足条件,所以最多暴力枚举 \(100\) 个即可。
B. Adjacent Tiles
因为目标是最小化暴露在外部的边数,所以也就是最小化图形的周长。假设整体可以容纳在一个 \(a \times b\) 的长方形中,周长为 \(2a+2b\),因此对于满足 \(a+b \ge n\) 的 \(a\) 和 \(b\),需要最小化 \(a+b\)。我们只需要考虑 \(\vert{}a-b\vert{} \le 1\) 的情况。
C. Ascending Labels
\(\text{DFS}\) 树上的深度满足条件。
D. Angst for All Pairs
按降序排列,并从 \(\text{popcount}\) 较小的开始使用。
E. ABC|AB|A
假设只能进行 \(A \to \varepsilon\)、\(AB \to D\)、\(D \to \varepsilon\)、\(DC \to \varepsilon\) 的重写操作。我们需要维护一个仅存放 \(A\) 和 \(D\) 的栈,从头开始遍历字符串 \(S\)。每当 \(B\) 或 \(C\) 无法被消除时,就更新答案。
还有一个更简单的做法:
可删子串为 "A"、"AB"、"ABC"。把字符串反转后,这三种删除对应的后缀是 "A"、"BA"、"CBA"。因此可以反过来从左向右在线维护一个栈,遇到可删的后缀就立即删除。
代码实现
void solve() {
string s;
cin >> s;
ranges::reverse(s);
string t;
for (char c : s) {
t += c;
char nc = 'A';
while (t.size() and t.back() == nc) {
t.pop_back();
nc++;
}
}
cout << t.size() << '\n';
}
F. AND/OR
虽然可以通过从高位到低位依次判定是否能置 1 来确定 \(M\),但深入思考这个判定就会发现,最终末尾 \(K\) 项的 \(\text{OR}\) 结果即为 \(M\)。我们可以从末尾开始,顺次考虑是选择 \(\text{OR}\) 还是 \(\text{AND}\) 。在不得不选 \(\text{OR}\) 的情况下很简单;而在 \(\text{OR}\) 和 \(\text{AND}\) 都可以选的情况下,如果选择了 \(\text{OR}\),所有位都会满足条件,此时剩余 \(\text{AND/OR}\) 的抉择方式可以表示为二项式系数之和 \(\sum\limits_{i \le b} \binom{a}{i} := f(a, b)\)。我们要计算的 \(f(a, b)\) 如果倒过来看的话,\(a\) 和 \(b\) 都是非递减的,因此这就变成了类似于莫队的转移中只进行指针增加的情况,总时间复杂度为 \(O(N)\)。
浙公网安备 33010602011771号