分段
首先看到一段区间的异或和就可以想到前缀和,先令 ,于是我们的要求就变成了对于每一个 求出 。
- [I] 容易想到亦或是不进位的加法,而通过与运算可以得到所有要进位的位,因此有恒等式 ,变形得到 。
应用到原式得到 ,即 。而 实际上是 减去所有 和 共有的 的位,当 此位为 或者 均为 时答案为 ,否则为 ,发现和 的逻辑一样( 是取反)。
- [p] 所以我们的任务就变成了对于每一个 ,找一个 使得 最大,答案就是这个表达式的值。
于是我就理所应当地想到了 01 字典树,毕竟涉及到位运算。对于我们需要配对的 ,贪心地从高到低枚举每一位,如果 这一位是 ,那么优先走 的那边,否则走 的那边。但是如果 这一位是 的话,问题就来了, 和 的两边都能走,如果都走的话那么时间复杂度就会爆炸。
具体来说,如果 当中有 个 ,那么单次查询最坏时间复杂度将会飙到 。当然,这里 的期望是 的,由于值域与 同阶(其实是分不清楚),单次查询期望时间复杂度是 的,当然可能会被极端数据卡掉。
不过我想到了一个妙招,就是把所有数取反了之后做按位并,答案再取反和直接做按位与是一样的,因此对于 多的就做按位并, 多的就做按位与,这样子最坏时间复杂度就控制到了 ,但变化不大。
- [c] 我就写的这个,挂 分。
其实我们离正解很近了。对于一个 位,字典树当中需要往两边递归导致复杂度爆炸,但是实际上我们并不需要实际递归下去。回到原式问题之中:
- [?] 我们为什么要用 01 字典树?
- [!] 因为它可以记录之前所有位的前缀。
也就是对于一个数,它必须在我们查询的前缀中才能被选中(也就是前缀是 的地方这个数也必须是 ,而 的地方任意)。这很像什么?前缀必须是我们选择的数的子集,所以我们会想到什么?子集 DP!
但是子集 DP 是离线的,如果非要在线处理需要枚举新加入的数的所有子集,这当然会超时,我们也不需要这种方式。可以把下标存进去,DP 的时候取 用来最后判断是否在要求的前缀 中。
设 表示所有包含 的超集中,最小的下标。收集型的转移就是枚举 中未出现 的位,然后对下标取最小值,即 。这个预处理的时间复杂度是 的。
对于查询,我们还是从高到低贪心地枚举位,尝试将这一位变成 ,不过所选择的数必须包含已选的前缀(即当前的 )且被包含在前缀 中。时间复杂度 。
- [n] 这道题目思维性质还是很强的,最开始的前缀和转换很简单但是位运算的推导需要灵活应用恒等式。最难的部分就是查询了,很多人像我一样都想到了在线地添加元素并查询,而详细用法的数据结构就是 01 字典树了,但是对于按位与很难解决需要双边递归的问题。其实只需要注意到 01 字典树的本质——高位前缀,转变思路离线下来用子集 DP 模拟前缀被覆盖的过程,并记录下标以满足 的前缀限制条件即可。
#include <iostream>
using namespace std;
using LL = long long;
const LL kMaxN = 1e6 + 5, kLog = 22;
LL a[kMaxN], dp[1 << kLog], n, ans;
LL query(LL x, LL p) {
LL res = 0;
for (LL i = kLog - 1; i >= 0; i--) {
if (!(x & (1 << i)) && dp[res | (1 << i)] <= p) {
res |= 1 << i;
}
}
return x + 2 * res;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n;
fill(begin(dp), end(dp), 1e9);
for (LL i = 1; i <= n; i++) {
cin >> a[i];
a[i] ^= a[i - 1];
dp[a[i]] = min(dp[a[i]], i);
}
dp[0] = 0;
for (LL i = (1 << kLog) - 1; i >= 0; i--) {
for (LL j = 0; j < kLog; j++) {
if (!(i & (1 << j))) {
dp[i] = min(dp[i], dp[i | (1 << j)]);
}
}
}
for (LL i = 1; i <= n; i++) {
ans ^= i * query(a[i], i);
}
cout << ans << '\n';
return 0;
}删除
我本来写了个简单的区间 DP,发现有些情况满足不了,所以就 WA 分了。
覆盖
啥也没写。
求和
啥也没写
总结
总分:。
这次考试不咋行,全肝 T1 最后没写出来,其实我已经离正解很近了。虽然我一题也没有写出来,不过 T1 的思路确实让我受益匪浅,失败是成功之母,下次再加油。T1 总结在上面。