题目大意
给定正整数 $ k, b, c, v $,求满足以下条件的非负整数 $ x $ 的数量:
其中 $ \oplus $ 表示异或运算。输入包含多组测试数据,每组数据的参数范围极大($ 10^{18} $ 级别)。
解题思路
核心思想:二进制位逐位分析
由于异或运算的性质,直接比较二进制位的大小关系。从最高位到最低位逐位确定 $ x $ 的取值范围,通过位运算将问题分解为多个独立的子问题。
关键步骤
1. 预处理函数
定义函数 get(l, r)
计算满足区间 $ [l, r] $ 内合法 $ x $ 的数量。其数学表达式为:
此函数用于快速统计区间内的合法 $ x $ 数量。
2. 逐位枚举
从最高位(62位)到最低位(0位)逐位处理:
- 对于当前位 $ i $:
- 若 $ v $ 的第 $ i $ 位为 $ 1 $:
- 当前位异或结果为 $ 0 $:此时 $ x $ 的取值范围受限于该位的约束。
- 当前位异或结果为 $ 1 $:此时该位的贡献可直接计入答案,后续位无需考虑。
- 若 $ v $ 的第 $ i $ 位为 $ 0 $:
- 当前位异或结果必须为 $ 0 $,否则直接返回无解。
- 若 $ v $ 的第 $ i $ 位为 $ 1 $:
3. 动态维护区间
使用变量 $ \text{now} $ 记录当前已确定的高位部分的异或结果。通过调整 $ \text{now} $ 的值,逐步缩小 $ x $ 的可能范围,并累加符合条件的 $ x $ 数量。
4. 特殊边界处理
最终需检查是否存在 $ x $ 使得 $ x \oplus c = v $,若存在则补全计数。
代码实现
以下是完整的代码实现:
#include<bits/stdc++.h>
#define int long long
using namespace std;const int N = 1e5 + 10;void solve() {int k, b, c, v;cin >> k >> b >> c >> v;// 定义函数 p(x),计算满足 (x - b) % k == 0 的最大 x 值auto p = [&](int x) {if (x < b) return 0ll;else if (x == b) return 1ll;else return (x - b) / k + 1ll;};int mx = 0;// 定义函数 get(l, r),计算区间 [l, r] 内合法 x 的数量auto get = [&](int l, int r) {mx = max(mx, p(r));return (p(r) - p(l - 1));};int now = 0, cnt = 0;// 逐位处理,从最高位到最低位for (int i = 62; i >= 0; i--) {if (v >> i & 1) { // 如果 v 的第 i 位为 1if (c >> i & 1) { // 如果 c 的第 i 位为 1now += (1ll << i); // 尝试设置当前位为 1cnt += get(now, now + (1ll << i) - 1); // 统计当前分支的贡献now -= (1ll << i); // 恢复状态} else { // 如果 c 的第 i 位为 0cnt += get(now, now + ((1ll << i) - 1)); // 直接统计当前分支的贡献now += (1ll << i); // 设置当前位为 1}} else if (c >> i & 1) { // 如果 v 的第 i 位为 0 且 c 的第 i 位为 1now += (1ll << i); // 必须设置当前位为 1}}// 最后检查是否存在恰好等于的情况now -= b;if (now >= 0 && now % k == 0) cnt++;cout << cnt << '\n';
}signed main() {ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);int T;cin >> T;while (T--) solve();return 0;
}
代码解析
1. 函数 p(x)
计算满足 $ x \bmod k = b $ 的最大 $ x $ 值:
2. 函数 get(l, r)
利用 $ p(x) $ 快速统计区间 $ [l, r] $ 内的合法 $ x $ 数量:
3. 逐位处理
通过位运算判断当前位的可能取值,动态调整 $ \text{now} $ 并累加答案。
4. 边界处理
最后检查是否存在恰好等于 $ x \oplus c = v $ 的情况,避免遗漏。
时间复杂度
算法的时间复杂度为:
其中 $ T $ 是测试数据组数,$ \log v $ 是逐位处理的最大迭代次数。对于 $ v \leq 10^{18} $,该算法可以轻松通过所有测试数据。