第 369 场 LeetCode 周赛题解

A 找出数组中的 K-or 值

在这里插入图片描述
在这里插入图片描述

模拟

class Solution {
public:
    int findKOr(vector<int> &nums, int k) {
        vector<int> cnt(32);
        for (auto x: nums)
            for (int i = 0; i < 32; i++)
                if (x >> i & 1)
                    cnt[i]++;
        int res = 0;
        for (int i = 0; i < 32; i++)
            if (cnt[i] >= k)
                res |= 1 << i;
        return res;
    }
};

B 数组的最小相等和

在这里插入图片描述

分类讨论:将两个数组中的 0 0 0 看作 1 1 1 求数组替换完后的最小数组和,若两个数组的最小数组和相等返回 0 0 0 ,否则只有最小数组和较小的一个数组存在 0 0 0 有解。

class Solution {
public:
    using ll = long long;

    long long minSum(vector<int> &nums1, vector<int> &nums2) {
        ll s1 = 0, s2 = 0;//两个数组的最小数组和
        bool have1 = false, have2 = false;//两个数组是否含有0
        for (auto x: nums1) {
            if (x)
                s1 += x;
            else {
                have1 = true;
                s1 += 1;
            }
        }
        for (auto x: nums2) {
            if (x)
                s2 += x;
            else {
                have2 = true;
                s2 += 1;
            }
        }
        if (s1 > s2) {
            swap(s1, s2);
            swap(have1, have2);
        }
        if (s1 == s2)
            return s1;

        return have1 ? s2 : -1;
    }
};

C 使数组变美的最小增量运算数

在这里插入图片描述
在这里插入图片描述

动态规划:设 p [ i ] p[i] p[i] 为将 n u m s [ 0 , i ] nums[0,i] nums[0,i] 变为美丽数组且满足 n u m s [ i ] ≥ k nums[i]\ge k nums[i]k 的最小递增运算数,有状态转移方程: p [ i ] = { m a x { k − n u m s [ i ] , 0 } i < 3 m i n { p [ i − 1 ] , p [ i − 2 ] , p [ i − 3 ] } + m a x { k − n u m s [ i ] , 0 } , i ≥ 3 p[i]=\left\{\begin{matrix} max\{k-nums[i],0\} & i<3 \\ min\{p[i-1],p[i-2],p[i-3] \}+max\{k-nums[i],0\} & ,i\ge 3 \end{matrix}\right. p[i]={max{knums[i],0}min{p[i1],p[i2],p[i3]}+max{knums[i],0}i<3,i3

class Solution {
public:
    using ll = long long;

    long long minIncrementOperations(vector<int> &nums, int k) {
        int n = nums.size();
        ll p[n];
        for (int i = 0; i < 3; i++)
            p[i] = max(k - nums[i], 0);
        for (int i = 3; i < n; i++) {
            p[i] = min({p[i - 1], p[i - 2], p[i - 3]}) + max(k - nums[i], 0);
        }
        return min({p[n - 1], p[n - 2], p[n - 3]});
    }
};

D 收集所有金币可获得的最大积分

在这里插入图片描述
在这里插入图片描述
记忆化搜索:设 p [ c u r ] [ c n t ] p[cur][cnt] p[cur][cnt] 为以 c u r cur cur 为根的子树在之前已经使用了 c n t cnt cnt 次第二种方法的情况下可获得的最大积分,有状态转移方程: p [ c u r ] [ c n t ] = m a x { ⌊ c o i n s [ c u r ] 2 c n t ⌋ − k + ∑ j ∈ s o n ( c u r ) p [ j ] [ c n t ] ⌊ c o i n s [ c u r ] 2 c n t + 1 ⌋ + ∑ j ∈ s o n ( c u r ) p [ j ] [ c n t + 1 ] p[cur][cnt]=max\left\{\begin{matrix} \left \lfloor \frac {coins[cur]} {2^{cnt}} \right \rfloor-k + \sum_{j\in son(cur)}p[j][cnt] \\ \left \lfloor \frac {coins[cur]} {2^{cnt+1}} \right \rfloor + \sum_{j\in son(cur)}p[j][cnt+1] \end{matrix}\right. p[cur][cnt]=max 2cntcoins[cur]k+json(cur)p[j][cnt]2cnt+1coins[cur]+json(cur)p[j][cnt+1]

class Solution {
public:
    int maximumPoints(vector<vector<int>> &edges, vector<int> &coins, int k) {
        int n = coins.size();
        vector<int> e[n];
        for (auto &ei: edges) {
            e[ei[0]].push_back(ei[1]);
            e[ei[1]].push_back(ei[0]);
        }
        int M = 16, inf = INT32_MIN;
        int p[n][M];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < M; j++)
                p[i][j] = inf;//初始化标志
        function<int(int, int, int)> dfs = [&](int cur, int cnt, int par) {//记忆化搜索
            if (p[cur][cnt] != inf)
                return p[cur][cnt];
            if (cnt == M - 1)//子树所有数已经为都0,接下来全用第二种方法
                return p[cur][cnt] = 0;
            int r1 = (coins[cur] >> cnt) - k, r2 = coins[cur] >> (cnt + 1);
            for (auto j: e[cur]) {
                if (j == par)
                    continue;
                r1 += dfs(j, cnt, cur);
                r2 += dfs(j, cnt + 1, cur);
            }
            return p[cur][cnt] = max(r1, r2);
        };
        return dfs(0, 0, -1);
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值