首页 > 其他 > 详细

Leetcode5700. 使所有区间的异或结果为零(DP)

时间:2021-03-07 22:04:41      阅读:33      评论:0      收藏:0      [点我收藏+]

题意

\(n\)个数和一个\(k\) 可以对一个数任意修改 要求修改最少的数 使得任意连续\(k\)个数 xor的和等于0
\(a[i] <= 2^{10}\)

题解

显然可以发现一个规律 假如\(k=3\)修改后的序列都形如\(abcabcabc\).... 相同字母表示相同的值
那么可以按\(k\)分组 \(a[i]\),\(a[i+k]\),\(a[i+2k]\)...的分为同一组 同一组的值最后是一样的
\(dp[val]\)表示已经枚举完了一些组 值为\(val\)的最小操作次数
转移有两种

1)全部修改为一个这组没出现的数

因为修改成的这个数可以是任意的 所以任意\(val\)的值都能由前面的最小值来转移过来

2)全部修改为一个这组出线过的一个数

依次枚举前面的\(val\)和选这一组出现过的一个数 单看这里以为总共的复杂度就是 \(O(k*k*2^{10})\) 就觉得不可做了
其实就是一个经典错误.. 和树上背包一样 其实复杂度是\(O(k* \frac{n}{k} *2^{10})\)

class Solution {
public:
    const int INF = 0x3f3f3f3f;
    int minChanges(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> dp(1 << 10, INF);
        dp[0] = 0;
        vector<unordered_map<int, int>> g(k);
        vector<int> sz(k);
        for(int i = 0; i < k; i++) {
            for(int j = i; j < n; j += k) {
                g[i][nums[j]]++;
                sz[i]++;
            }
        }
        for(int i = 0; i < k; i++) {
            int zx = *min_element(dp.begin(), dp.end());
            vector<int> tmp(1 << 10, zx + sz[i]);
            for(int j = 0; j < (1 << 10); j++) {
                if(dp[j] == INF) continue;
                for(auto [a, b] : g[i]) {
                    int nx = a ^ j;
                    tmp[nx] = min(tmp[nx], dp[j] + sz[i] - b);
                }
            }
            dp = move(tmp);
        }
        return dp[0];
    }
};

Leetcode5700. 使所有区间的异或结果为零(DP)

原文:https://www.cnblogs.com/lwqq3/p/14496058.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!