1 条题解
-
0
题意回顾
- 有 轮,第 轮时,如果 ,水母(最小化者)操作;如果 ,花花(最大化者)操作。
- 操作: 或 。
- 初始 ,问最优情况下最后的 。
核心思路
第一步:变量转化
设初始 ,但更方便的是设初始 ,这样选择 相当于 不变,选择 相当于 再异或上 。
令
那么在第 轮:
- 选择 : 不变
- 选择 :
所以游戏变成:
- 初始
- 对 ,如果 (水母),她可以选择 不变或 ,并希望最终 最小;
如果 (花花),她选择 不变或 ,希望最终 最大。
这是一个带选择权的线性基博弈。
第二步:逆序处理
从后往前考虑。
设 表示从当前轮开始到结束,在双方最优策略下最终的 值(当前 是某个初始值)。
我们发现 是仿射变换:其中 是一个线性(异或)变换(可逆? 不一定全空间), 是一个常数向量(异或意义上)。
当 时,,即 。
第三步:一次逆序递推
假设我们从后面前已经处理好了后面的 轮,得到了当前 。
现在考虑前面的一轮,给定 和 (最小化/最大化)。该轮操作后:
- 如果不异或 ,结果 =
- 如果异或 ,结果 =
因为:
$$f(x \oplus d_i) = A (x \oplus d_i) \oplus b = (A x \oplus b) \oplus (A d_i) = f(x) \oplus (A d_i) $$所以两选项的差异是常数 。
关键:设 。
如果 (水母,最小化者),她会在 和 中选择更小的。
如果 (花花,最大化者),她会选更大的。这决定依赖于 的最高不同位(即 的最高位 )在 中是 0 还是 1。
第四步:线性基维护
我们要维护 和 的信息。
实际上, 是一个线性变换,我们可以用线性基来表示它的零空间和像空间。标程的做法是:
- 用一个线性基
bas来存储所有 经过 映射后的值(即 )的一些信息。 - 给基向量打标记
bel[i],表示这个基向量对应的 在插入时,是由最小化者还是最大化者控制的。
具体:
- 初始化 (空基)。
- 从 到 逆序处理:
- 令
- 把 插入到线性基中(用标准的线性基插入,但要保证基是上三角形式)
- 在插入时,如果 变成非零基向量,那么它的最高位 对应 的最高位,决定它是“增加”还是“减少”。
这里的
bel[k]标记这个基向量是由谁控制的( 或 )。
第五步:最终计算
在逆序过程中,我们实际上在做:
- 从后往前,每个 可能会引入新的基向量(如果不被已有基表示),这个基向量可以理解为 在像空间的一个坐标轴。
- 所有 的控制者决定了这个轴在最终 中是保留还是取消(因为最优策略会选)。
最终:
- 初始
- 然后把 在基中尽量消去(即从高到低,如果 某位有 1,则异或对应的基向量),表示最终 的“不可控部分”。
- 再把所有 (花花控制)的基向量异或回 ,表示这些是花花可以强制变成 1 的位。
最终答案 = 。
代码实现
int n; std::cin >> n; std::vector<i64> a(n), b(n); std::string str; i64 all = 0; for(auto &x : a) std::cin >> x, all ^= x; // 初始 all = XOR a_i for(int i = 0; i < n; i ++) { std::cin >> b[i]; b[i] ^= a[i]; // 变成 d_i = a_i ^ b_i } std::cin >> str; // c 字符串 std::vector<i64> bas(L); // 线性基 std::vector<int> bel(L, -1); // 基向量的控制者标记 for(int i = n - 1; i >= 0; i --) { // 逆序处理 i64 x = b[i]; // x = d_i int col = str[i] - '0'; // 0 或 1 // 标准线性基插入,但要保持上三角形式 for(int i = L - 1; i >= 0; i --) if(x >> i & 1) { if(bas[i]) { x ^= bas[i]; } else { // 消去低位 for(int j = i - 1; j >= 0; j --) if(x >> j & 1) { x ^= bas[j]; } bas[i] = x; // 消去高位 for(int j = L - 1; j > i; j --) if(bas[j] >> i & 1){ bas[j] ^= bas[i]; } bel[i] = col; // 记录这个基向量的控制者 break; } } } // all 在基中消去 for(int i = L - 1; i >= 0; i --) if(all >> i & 1) { all ^= bas[i]; } // 收集花花(控制者 1)可以控制的基向量 i64 ans = 0; for(int i = 0; i < L; i ++) if(bel[i] == 1) ans ^= bas[i]; std::cout << (all ^ ans) << '\n';
复杂度
- 每个 插入线性基
- 总和 ,每位 位
- 总复杂度
总结
该解法核心:
- 把 转化为 和初始 。
- 逆序处理,用线性基维护 的信息。
- 通过基向量控制者标记,决定哪些位最终能被花花固定为 1。
- 最后得到答案。
- 1
信息
- ID
- 7194
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者