小猫 round 比赛总结
分数:\(50 + 90 + 0 + 45 = 185\)
梗最多的一集。
T1
神秘 ad-hoc,把我和 AeeE5x 坑惨了,反而让 hiphop 捞着了。
这道题中对贡献的描述乍一看有些莫名其妙,但实际上,就是一旦在序列中添加一个端点,那么贡献就会加上此处的后缀和。所以,我们只需要贪心地取前 \(k\) 个最大且 \(>0\) 的贡献即可。
#include <bits/stdc++.h>
#define int long long
const int N = 1e5+10;
int T, n, k, suf[N]; std::string s;
signed main() {
freopen("sail.in", "r", stdin);
freopen("sail.out", "w", stdout);
std::ios::sync_with_stdio(false); std::cin.tie(0);
std::cin >> T;
while (T--) {
std::cin >> n >> k >> s;
s = " " + s;
suf[n+1] = 0;
for (int i = n; i >= 1; i--) {
suf[i] = suf[i+1] + (s[i] == '1' ? 1 : -1);
}
std::priority_queue<int> q;
for (int i = n; i > 1; i--) {
q.push(suf[i]);
}
int sum = 0, ans = 0;
while (!q.empty()) {
if (q.top() <= 0) break;
sum += q.top();
q.pop();
ans++;
if (sum >= k) break;
}
if (sum < k) std::cout << -1 << '\n';
else std::cout << ans + 1 << '\n';
}
return 0;
}
T2
这道题场上把最难的部分攻下了,却忽略了 \(n = 1\) 这一最简单的情况,与 AC 失之交臂。一定要特判 \(n = 1\),原因稍后会讲。
以编号记录节点不太直观,我们考虑以数对 \((a, b)\) 记录节点,表示这是第 \(a\) 层从左往右数第 \(b\) 个节点,其中根节点的层数记为 \(0\)。
可以推出,节点 \((a, b)\) 的编号为 \(\sum_{i = 0}^{a - 1}n^i + b\)。
小科普
\[\sum\limits_{i=0}^{m}n^i = \frac{n^{m+1}-1}{n-1} \]这会用于我们稍后的代码中。从中也能看到,当 \(n = 1\) 时,\(0\) 会成为分母(由于要取模,在代码中实际表现为求 \(0\) 的逆元),这就是为什么要对 \(n=1\) 的情况进行特判。
考虑到 \((a, b)\) 左边的 \((b-1)\) 个节点分别都有 \(n\) 个儿子,因此节点 \((a, b)\) 的第 \(c\) 个儿子可以表示为 \((a+1, (b-1)n + c)\)。但是本题的难点在于如何求走 \(y\) 步后到达的节点。其层数显然为 \(a+y\),我们只讨论其在一层的位置 \(b_y\)。设 \(f(b, c) = (b-1)n+c\),则
还剩最后一个难点:如何求节点 \((a, b)\) 的 \(y\) 级祖先?如果这道题没有取模,直接对 \(n\) 进行对 \(n\) 取模相关操作即可,但是考虑到此题要对 \(998244353\) 取模,直接求解比较困难。不过我们有一种间接求解的方式 —— “回望来路”。
在我们刚才求儿子的时候,我们每从一个节点出发,就把它连同此时的方向压入一个栈中。当我们要求解祖先时,可以不停地弹出栈顶元素,直到其深度小于要求解祖先的深度,这意味着我们找到了一个我们曾经走过的,且比要求的点高的节点 \((a', b')\)。于是我们就把求解 \((a, b)\) 的祖先转化成了求 \((a', b')\) 的后代。注意方向为此前记录的方向。
#include <bits/stdc++.h>
#define int long long
const int N = 1e5+10, MOD = 998244353;
int n, q;
int qpow(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
void exgcd(int a, int b, int &x, int &y) {
if (!b) {x = 1, y = 0; return;}
else exgcd(b, a%b, y, x), y -= a / b * x;
}
int getInv(int a) {
int x = 0, y = 0;
exgcd(a, MOD, x, y);
return x % MOD;
}
int jiheJishu(int n, int m) {
return ((qpow(n, m + 1) - 1) * getInv(n - 1)) % MOD;
}
int rangeJHJS(int a, int b) {
if (a == 0) return jiheJishu(n, b);
return (jiheJishu(n, b) - jiheJishu(n, a-1) % MOD + MOD) % MOD;
}
struct Node {
int level, id;
};
int NodeToNum(Node node) {
return ((rangeJHJS(0, node.level - 1) + node.id) % MOD + MOD) % MOD;
}
Node getSon(Node ori, int c, int y) {
if (y == 0) return ori;
int a = ori.level, b = ori.id;
Node res;
res.level = a + y;
res.id = (qpow(n, y) * b) % MOD - qpow(n, y) + ((c - 1) * (rangeJHJS(1, y - 1))) % MOD + c;
if (res.id < 0) res.id += MOD;
return res;
}
std::stack<std::pair<Node, int> > stk;
signed main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
std::ios::sync_with_stdio(false); std::cin.tie(0);
std::cin >> n >> q;
if (n == 1) {
int curr = 1;
while (q--) {
int x, y;
std::cin >> x >> y;
if (x == 0) {
curr -= y;
} else {
curr += y;
}
std::cout << curr << '\n';
}
return 0;
}
Node curr = {0, 1};
while (q--) {
int x, y;
std::cin >> x >> y;
if (x == 0) {
while (stk.top().first.level > curr.level - y) {
stk.pop();
}
curr = getSon(stk.top().first, stk.top().second, curr.level - y - stk.top().first.level);
std::cout << NodeToNum(curr) << '\n';
continue;
}
stk.push({curr, x});
curr = getSon(curr, x, y);
std::cout << NodeToNum(curr) << '\n';
}
return 0;
}

浙公网安备 33010602011771号