题目描述
给你一个整数数组 nums 和一个整数 k 。区间 [left, right](left <= right)的 异或结果 是对下标位于 left 和 right(包括 left 和 right )之间所有元素进行 XOR 运算的结果:nums[left] XOR nums[left+1] XOR ... XOR nums[right] 。
返回数组中 要更改的最小元素数 ,以使所有长度为 k 的区间异或结果等于零。
思路分析
- 分组背包:按照区间长度为k的求模来分为k个组
- 状态转移函数f(i,mask)=min{f(i−1,mask⊕x)+size(i)−count(i,x)}
- 优化为两个部分
-
将
f(i−1,mask⊕x)-count(i,x)
分为f(i−1,mask⊕x)
和f(i−1,mask⊕x)-count(i,x)
-
这里的
f(i−1,mask⊕x)
可以直接通过*min_element(f.begin(), f.end())
获取最小元素(后面>i的已经通过vector<int> f(MAXX, n)
取最大值了)
-
- 优化为两个部分
官方题解如下
- 基于官方题解,修改了部分
-
class Solution { private: // x 的范围为 [0, 2^10) static constexpr int MAXX = 1 << 10; public: int minChanges(vector<int>& nums, int k) { int n = nums.size(); vector<int> f(MAXX, n); // 边界条件 f(-1,0)=0 f[0] = 0; for (int i = 0; i < k; ++i) { // 第 i 个组的哈希映射 unordered_map<int, int> cnt; int size = 0; for (int j = i; j < n; j += k) { ++cnt[nums[j]]; ++size; } // 求出 t2 int t2min = *min_element(f.begin(), f.end()); vector<int> g(MAXX, t2min); for (int mask = 0; mask < MAXX; ++mask) for (auto [x, countx]: cnt) g[mask] = min(g[mask], f[mask ^ x] - countx); // 别忘了加上 size for(auto &t:g) t+=size; f = g; } return f[0]; } };