We use bitmask DP to represent which numbers have been used. For each operation, we try all pairs of unused numbers, calculate the score, and recursively solve for the remaining numbers. Memoization helps avoid recomputation.
classSolution {
publicintmaxScore(int[] nums) {
int n = nums.length, m = n/2;
int[][] g =newint[n][n];
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
g[i][j]= gcd(nums[i], nums[j]);
int[] dp =newint[1<<n];
for (int mask = 0; mask < (1<<n); ++mask) {
int cnt = Integer.bitCount(mask);
if (cnt % 2 != 0) continue;
for (int i = 0; i < n; ++i) {
if ((mask & (1<<i)) == 0) continue;
for (int j = i+1; j < n; ++j) {
if ((mask & (1<<j)) == 0) continue;
int newMask = mask ^ (1<<i) ^ (1<<j);
int op = m - cnt/2 + 1;
dp[mask]= Math.max(dp[mask], dp[newMask]+ op * g[i][j]);
}
}
}
return dp[(1<<n)-1];
}
privateintgcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
}
classSolution {
funmaxScore(nums: IntArray): Int {
val n = nums.size
val m = n/2val g = Array(n) { IntArray(n) }
for (i in0 until n)
for (j in0 until n)
g[i][j] = gcd(nums[i], nums[j])
val dp = IntArray(1 shl n)
for (mask in0 until (1 shl n)) {
val cnt = mask.countOneBits()
if (cnt % 2!=0) continuefor (i in0 until n) {
if (mask and (1 shl i) ==0) continuefor (j in i+1 until n) {
if (mask and (1 shl j) ==0) continueval newMask = mask xor (1 shl i) xor (1 shl j)
val op = m - cnt/2 + 1 dp[mask] = maxOf(dp[mask], dp[newMask] + op * g[i][j])
}
}
}
return dp[(1 shl n)-1]
}
privatefungcd(a: Int, b: Int): Int {
var x = a; var y = b
while (y !=0) {
val t = y; y = x % y; x = t
}
return x
}
}
classSolution:
defmaxScore(self, nums: list[int]) -> int:
from math import gcd
n, m = len(nums), len(nums)//2 g = [[gcd(nums[i], nums[j]) for j in range(n)] for i in range(n)]
dp = [0] * (1<<n)
for mask in range(1<<n):
cnt = bin(mask).count('1')
if cnt %2!=0:
continuefor i in range(n):
ifnot (mask & (1<<i)):
continuefor j in range(i+1, n):
ifnot (mask & (1<<j)):
continue new_mask = mask ^ (1<<i) ^ (1<<j)
op = m - cnt//2+1 dp[mask] = max(dp[mask], dp[new_mask] + op * g[i][j])
return dp[(1<<n)-1]
impl Solution {
pubfnmax_score(nums: Vec<i32>) -> i32 {
fngcd(mut a: i32, mut b: i32) -> i32 {
while b !=0 {
let t = b; b = a % b; a = t;
}
a
}
let n = nums.len();
let m = n/2;
letmut g =vec![vec![0; n]; n];
for i in0..n {
for j in0..n {
g[i][j] = gcd(nums[i], nums[j]);
}
}
letmut dp =vec![0; 1<<n];
for mask in0..(1<<n) {
let cnt = mask.count_ones();
if cnt %2!=0 { continue; }
for i in0..n {
if mask & (1<<i) ==0 { continue; }
for j in i+1..n {
if mask & (1<<j) ==0 { continue; }
let new_mask = mask ^ (1<<i) ^ (1<<j);
let op = m - cnt/2+1;
dp[mask asusize] = dp[mask asusize].max(dp[new_mask asusize] + op asi32* g[i][j]);
}
}
}
dp[(1<<n)-1]
}
}
Try all possible pairings using backtracking, but prune branches that cannot beat the current best score. This is slower but can be useful for small n.
defmaxScore(nums: list[int]) -> int:
from math import gcd
n, m = len(nums), len(nums)//2 g = [[gcd(nums[i], nums[j]) for j in range(n)] for i in range(n)]
best =0defdfs(op: int, used: int, score: int):
nonlocal best
if op > m:
best = max(best, score)
returnfor i in range(n):
if used & (1<<i): continuefor j in range(i+1, n):
if used & (1<<j): continue dfs(op+1, used | (1<<i) | (1<<j), score + op * g[i][j])
dfs(1, 0, 0)
return best