Leetcode.1799 N 次操作后的最大分数和
题目链接
Leetcode.1799 N 次操作后的最大分数和 Rating : 2073
题目描述
给你 nums
,它是一个大小为
2
∗
n
2 * n
2∗n 的正整数数组。你必须对这个数组执行
n
n
n 次操作。
在第 i 次操作时(操作编号从 1 开始),你需要:
- 选择两个元素 x 和 y 。
- 获得分数 i ∗ g c d ( x , y ) i * gcd(x, y) i∗gcd(x,y) 。
- 将 x 和 y 从
nums
中删除。
请你返回 n 次操作后你能获得的分数和最大为多少。
函数 g c d ( x , y ) gcd(x, y) gcd(x,y) 是 x 和 y 的最大公约数。
示例 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==2∗n
- 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(2m−1) 就是答案。
限制: 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/2∗g[i][j]}。
时间复杂度: O ( m 2 l o g C + 2 m ∗ m 2 ) O(m^2logC + 2^m * m^2) O(m2logC+2m∗m2)
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];
}
};
相关文章
- 【程序源代码】docker精选操作
- 2022-11-11:设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素。 实现 MaxStack 类: MaxStack() 初始化栈对象 void
- 2022-11-11:设计一个最大栈数据结构,既支持栈操作,又支持查找栈中最大元素。实现 MaxStack 类:MaxStack
- MongoDB操作:提升工作效率的绝佳工具(mongodb操作工具)
- 使用VBA操作Oracle — 学会如何发挥它的最大威力(vba操作oracle)
- Linux下NCFTP操作技术指南(linuxncftp)
- Linux下撤销命令:恢复前一次操作(linux下撤销命令)
- MySQL字符串操作之获取最大价值(mysql字符串的值)
- Linux下查看账户密码简易操作(linux查看账户密码)
- 模式 Linux开启单用户模式:立即操作!(linux启动单用户)
- Linux重定向追加:实现简单指令操作的功能(linux重定向追加)
- 借助MSSQL实现取最大日期的简易操作(取最大日期mssql)
- 查看Redis中所有键值对一步操作解决问题(查看redis中key)
- 云redis极速连接,轻松实现远程操作(云redis如何连接)
- Oracle中组合函数简易操作,搞定复杂统计(oracle中组合函数)
- Oracle数据库下进行视图替换的操作(oracle中替换视图)