1 条题解
-
0
题目理解
我们有两个多重集 和 ,大小均为 。
可以对 中的某个元素 做如下操作:- 删除 ,然后插入 或 。
问:能否经过任意次操作,使 变成 ?
关键数学观察
操作的本质是:
可以变成 或 。
考虑 对 取模:设 ()。
- 对 取模仍是 。
- 对 取模是 ,即 或 。
重要结论:
$$x \equiv y \pmod{k} \quad \text{或} \quad x + y \equiv 0 \pmod{k}. $$
一个元素 可以变成另一个元素 当且仅当证明
-
若
假设 ,可以反复执行 ,直到变成 。
若 ,则反复执行 并注意控制方向,可以归约到 。 -
若
可以先将 变成 (通过反复减去 或变成 来调整),
再变成 ,此时 ,
再利用情况 1 变成 。
化简思路
因此,对于任意元素 ,我们可以只关注它在模 意义下的最小非负代表,但注意:
由于 可以变成 或 ,
这两个值中更小的那个就是它能达到的“最简形式”。定义:
$$f(x) = \min(x \bmod k,\; (k - (x \bmod k)) \bmod k) $$为什么取 ?
因为 和 两者代表的“剩余类”在操作下是等价的(互变),所以我们统一映射到较小的那个,用于比较两个多重集是否可能相等。
算法步骤
- 读入 和两个多重集 (原 )和 (目标 )。
- 对 中每个元素 ,计算 ,再计算 ,用哈希表计数 。
- 对 中每个元素 ,同样计算 ,然后 。
- 如果最终哈希表中所有计数都为 ,说明 和 在“最小代表”意义下匹配,输出
"YES",否则"NO"。
为什么用随机哈希(XOR RD)
题目中 可达 , 的范围是 ,直接用 做哈希键没问题,但为了防止卡哈希(hacking 或刻意构造冲突),代码中用了一个随机数 ,将键变成 ,这样攻击者无法预知哈希函数。
在 C++ 中,直接用 也可以 AC,但加上随机化更安全。
例子验证
样例 3
- ,
- ,
- ,
的计数:
- ,
- ,
- ,
的计数:
完全匹配
YES
复杂度
- 每个元素 处理。
- 总复杂度 。
- 满足 总和 。
最终代码(C++,无随机化简化版,易于理解)
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { int n, k; cin >> n >> k; vector<int> A(n), B(n); for (int i = 0; i < n; i++) cin >> A[i]; for (int i = 0; i < n; i++) cin >> B[i]; map<int, int> cnt; for (int x : A) { int r = x % k; cnt[min(r, k - r)]++; } for (int x : B) { int r = x % k; cnt[min(r, k - r)]--; } bool ok = true; for (auto& [_, v] : cnt) { if (v != 0) { ok = false; break; } } cout << (ok ? "YES" : "NO") << '\n'; } return 0; }
- 1
信息
- ID
- 7043
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者