给你 nums
,它是一个大小为 2 * n
的正整数数组。你必须对这个数组执行 n
次操作。
在第 i
次操作时(操作编号从 1 开始),你需要:
- 选择两个元素
x
和y
。 - 获得分数
i * gcd(x, y)
。 - 将
x
和y
从nums
中删除。
请你返回 n
次操作后你能获得的分数和最大为多少。
函数 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
nums.length == 2 * n
1 <= nums[i] <= 106
方法一:状态压缩 + 动态规划
我们可以先预处理得到数组 nums
中任意两个数的最大公约数,存储在二维数组
然后定义 nums
中的元素个数,那么状态一共有
从小到大枚举所有状态,对于每个状态
枚举
最终答案即为
时间复杂度 nums
中的元素个数。
class Solution:
def maxScore(self, nums: List[int]) -> int:
m = len(nums)
g = [[0] * m for _ in range(m)]
for i in range(m):
for j in range(i + 1, m):
g[i][j] = gcd(nums[i], nums[j])
f = [0] * (1 << m)
for k in range(1 << m):
if (cnt := k.bit_count()) % 2 == 0:
for i in range(m):
if k >> i & 1:
for j in range(i + 1, m):
if k >> j & 1:
f[k] = max(
f[k],
f[k ^ (1 << i) ^ (1 << j)] + cnt // 2 * g[i][j],
)
return f[-1]
class Solution {
public int maxScore(int[] nums) {
int m = nums.length;
int[][] g = new int[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[] f = new int[1 << m];
for (int k = 0; k < 1 << m; ++k) {
int cnt = Integer.bitCount(k);
if (cnt % 2 == 0) {
for (int i = 0; i < m; ++i) {
if (((k >> i) & 1) == 1) {
for (int j = i + 1; j < m; ++j) {
if (((k >> j) & 1) == 1) {
f[k] = Math.max(f[k], f[k ^ (1 << i) ^ (1 << j)] + cnt / 2 * g[i][j]);
}
}
}
}
}
}
return f[(1 << m) - 1];
}
private int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
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 f[1 << m];
memset(f, 0, sizeof f);
for (int k = 0; k < 1 << m; ++k) {
int cnt = __builtin_popcount(k);
if (cnt % 2 == 0) {
for (int i = 0; i < m; ++i) {
if (k >> i & 1) {
for (int j = i + 1; j < m; ++j) {
if (k >> j & 1) {
f[k] = max(f[k], f[k ^ (1 << i) ^ (1 << j)] + cnt / 2 * g[i][j]);
}
}
}
}
}
}
return f[(1 << m) - 1];
}
};
func maxScore(nums []int) int {
m := len(nums)
g := [14][14]int{}
for i := 0; i < m; i++ {
for j := i + 1; j < m; j++ {
g[i][j] = gcd(nums[i], nums[j])
}
}
f := make([]int, 1<<m)
for k := 0; k < 1<<m; k++ {
cnt := bits.OnesCount(uint(k))
if cnt%2 == 0 {
for i := 0; i < m; i++ {
if k>>i&1 == 1 {
for j := i + 1; j < m; j++ {
if k>>j&1 == 1 {
f[k] = max(f[k], f[k^(1<<i)^(1<<j)]+cnt/2*g[i][j])
}
}
}
}
}
}
return f[1<<m-1]
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func gcd(a, b int) int {
if b == 0 {
return a
}
return gcd(b, a%b)
}