比赛链接
好消息:永康喵喵这回没翻车,没有爆零或挂分!
坏消息:T2 这道唐题竟然没看懂题意,相当于不知道怎么踩油门!
T1
一道非常简单的贪心。虽然现在看来十分简单,但是在场上想了好多种假的做法,毕竟贪心这种东西的核心就是连蒙带猜。不过最后还是场切了。
简单说来,就是从左到右遍历每一根杆子,先尝试往左放,如果放不了就往右放,如果还是放不了就放弃。
T2
如果读懂题意,这道题就是完全的唐题。可惜我这四个月来学了不少东西,却不知道二分图是什么,遗憾离场。
什么是二分图呢?简单来说,这种图的点可以划分为两部分,使得同一部分中的点没有直接相连的边。
那么问题就很简单了。我们可以把左边和右边的点分别进行排序,然后计算出 \(\max(b_i - a_i, 0)\) 的前缀最大值和 \(\max(b_{i+1} - a_i, 0)\) 的后缀最大值,然后对于每一个 \(i\),计算出 \(\max(\mathrm{premax}_{i-1}, \mathrm{sufmax}_{i})\),最后把答案按原顺序还原输出即可。
#include <bits/stdc++.h>
const int N = 2e5+10;
typedef long long ll;
int n, a[N], b[N], pre1[N], suf2[N], order[N], ans[N];int main() {std::ios::sync_with_stdio(false), std::cin.tie(0);std::cin >> n;n++;for (int i = 1; i <= n; i++) {std::cin >> b[i];}for (int i = 1; i <= n - 1; i++) {std::cin >> a[i];}for (int i = 1; i <= n; i++) {order[i] = i;}std::sort(order+1, order+1+n, [](int x, int y) {return b[x] < b[y];});std::sort(a+1, a+n);std::sort(b+1, b+1+n);for (int i = 1; i <= n - 1; i++) {pre1[i] = std::max(pre1[i-1], std::max(b[i] - a[i], 0));}for (int i = n-1; i >= 1; i--) {suf2[i] = std::max(suf2[i+1], std::max(b[i+1]-a[i], 0));}for (int i = 1; i <= n; i++) {ans[order[i]] = std::max(pre1[i-1], suf2[i]);}for (int i = 1; i <= n; i++) {std::cout << ans[i] << ' ';}std::cout << '\n';return 0;
}
T3
这道题的测试点数据设计真是太妙了,每个测试点的数据范围都不一样且递增,具有很好的区分性。
言归正传,这道题要求 \(1 \sim n\) 中每个数的因数的异或和的异或和。如果你注意力惊人,可以注意到,对于每个因子 \(d\),它在最终答案中出现的次数即为 \(\lfloor \frac{n}{d} \rfloor\),且只有当 \(\lfloor \frac{n}{d} \rfloor\) 为奇数时,才会被计入最终答案。因此,题意可以转化为:
求所有满足 \(\lfloor \frac{n}{d} \rfloor\) 为奇数的 \(d\) 的异或和。
这道题很多人(包括我的 DeepSeek)的第一反应应该是数论分块。然而当你兴高采烈地提交这样的代码,就会发现最后一个测试点以 1037 ms 成功 TLE。在 AeeE5x 大神的指导下,我尝试使用了根号分治:对于\(x < \sqrt{n}\),枚举因子;对于 \(x > \sqrt{n}\),枚举 \(\lfloor \frac{n}{x} \rfloor\)。
#include <bits/stdc++.h>
typedef long long ll;inline ll xorSum(ll n) {switch (n & 3) {case 0:return n;case 1:return 1;case 2:return n + 1;default:return 0;}
}int main() {freopen("div.in", "r", stdin);freopen("div.out", "w", stdout);std::ios::sync_with_stdio(false); std::cin.tie(0);ll n;std::cin >> n;register ll ans = 0;ll sqrtN = sqrt(n);for (ll x = 1; x <= sqrtN; x++) {if ((n / x) & 1) {ans ^= x;}}for (ll k = 1; k <= sqrtN; k++) {if (k & 1) {ll l = n / (k + 1) + 1;ll r = n / k;if (l <= sqrtN) l = sqrtN + 1;if (l > r) continue;ans ^= xorSum(r) ^ xorSum(l - 1);}}std::cout << ans << '\n';return 0;
}
请注意以上代码使用了快速计算连续整数异或和的技巧。
总结
菜就多练,学得少就多学。
