zl程序教程

您现在的位置是:首页 >  其它

当前栏目

Leetcode.1799 N 次操作后的最大分数和

操作 最大 分数
2023-09-14 09:01:26 时间

题目链接

Leetcode.1799 N 次操作后的最大分数和 Rating : 2073

题目描述

给你 nums,它是一个大小为 2 ∗ n 2 * n 2n 的正整数数组。你必须对这个数组执行 n n n 次操作。

在第 i 次操作时(操作编号从 1 开始),你需要:

  • 选择两个元素 xy
  • 获得分数 i ∗ g c d ( x , y ) i * gcd(x, y) igcd(x,y)
  • xynums中删除。

请你返回 n 次操作后你能获得的分数和最大为多少。

函数 g c d ( x , y ) gcd(x, y) gcd(x,y)xy最大公约数

示例 1:

输入:nums = [1,2]
输出:1
解释:最优操作是:
(1 * gcd(1, 2)) = 1

示例 2:

输入:nums = [3,4,6,8]
输出:11
解释:最优操作是:
(1 * gcd(3, 6)) + (2 * gcd(4, 8)) = 3 + 8 = 11

示例 3:

输入:nums = [1,2,3,4,5,6]
输出:14
解释:最优操作是:
(1 * gcd(1, 5)) + (2 * gcd(2, 4)) + (3 * gcd(3, 6)) = 1 + 4 + 9 = 14

提示:

  • 1 < = n < = 7 1 <= n <= 7 1<=n<=7
  • n u m s . l e n g t h = = 2 ∗ n nums.length == 2 * n nums.length==2n
  • 1 < = n u m s [ i ] < = 1 0 6 1 <= nums[i] <= 10^6 1<=nums[i]<=106

解法:状压dp

预处理:

定义一个二维数组 g g g g [ i ] [ j ] = g c d ( n u m s [ i ] , n u m s [ j ] ) g[i][j] = gcd(nums[i] , nums[j]) g[i][j]=gcd(nums[i],nums[j]),方便我们快速的获得 n u m s [ i ] 和 n u m s [ j ] nums[i] 和 nums[j] nums[i]nums[j] 的最大公因数。

m = n u m s . s i z e ( ) m = nums.size() m=nums.size(),我们用一个二进制数 2 m 2 ^ m 2m 表示 n u m s [ i ] nums[i] nums[i] 选还是不选。

我们定义 f ( m a s k ) f(mask) f(mask) 为状态是 m a s k mask mask 的情况下的最大分数和,按照定义, f ( 2 m − 1 ) f(2^m-1) f(2m1) 就是答案。

限制: m a s k mask mask中 1 的个数(我们用 k k k 来表示) 必须是偶数,因为我们每次都是选择两个数进行操作的。

当前状态为 m a s k mask mask,选择了 n u m s [ i ] 和 n u m s [ j ] nums[i] 和 nums[j] nums[i]nums[j] 的情况:
f ( m a s k ) = m a x { f ( m a s k ) , f ( m a s k − ( 2 i ) − ( 2 j ) ) + k / 2 ∗ g [ i ] [ j ] } f(mask) = max \{ f(mask) , f(mask - (2^i) - (2^j)) + k/2 * g[i][j] \} f(mask)=max{f(mask),f(mask(2i)(2j))+k/2g[i][j]}

时间复杂度: O ( m 2 l o g C + 2 m ∗ m 2 ) O(m^2logC + 2^m * m^2) O(m2logC+2mm2)

C++代码:


class Solution {
public:
    int maxScore(vector<int>& nums) {
        int m = nums.size();
        int g[m][m];
        for(int i = 0;i < m;i++){
            for(int j = i + 1;j < m;j++){
                g[i][j] = gcd(nums[i],nums[j]);
            }
        }

        int len = (1 << m);
        int f[len];
        memset(f,0,sizeof f);

        for(int mask = 3;mask < len;mask++){
            int k = __builtin_popcount(mask);
            if(k & 1) continue;
            for(int i = 0;i < m;i++){
                if((mask >> i) & 1){
                    for(int j = i + 1;j < m;j++){
                        if((mask >> j) & 1){
                            f[mask] = max(f[mask] , f[mask ^ (1 << i) ^ (1 << j)] +k/2*g[i][j]);
                        }
                    }
                }
            }
        }

        return f[len-1];
    }
};