LeetCode 5695. N 次操作后的最大分数和(状压dp)

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

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

选择两个元素 x 和 y 。
获得分数 i * gcd(x, y) 。
将 x 和 y 从 nums 中删除。
请你返回 n 次操作后你能获得的分数和最大为多少。

函数 gcd(x, y) 是 x 和 y 的最大公约数。

数据范围:
1 <= n <= 7
nums.length == 2 * n
1 <= nums[i] <= 1e6
解法:
令d[i][j]表示i次操作,当前剩余数状态为j的最大权值和.其中j是一个二进制数.
枚举j中未使用的数的下标x和y进行转移.
d[i][j]可以转移到d[i+1][j^(1<<x)^(1<<y)],转移收益为gcd(a[x],a[y]).
code:
int d[10][(1<<14)];
class Solution {
public:
    int maxScore(vector<int>& a) {
        int n=a.size();
        for(int i=0;i<=n/2;i++){
            for(int j=0;j<(1<<n);j++){
                d[i][j]=-2e9;
            }
        }
        d[0][(1<<n)-1]=0;
        for(int i=0;i<n/2;i++){
            for(int j=0;j<(1<<n);j++){
                if(d[i][j]==-2e9)continue;
                for(int x=0;x<n;x++){
                    if(j>>x&1){
                        for(int y=x+1;y<n;y++){
                            if(j>>y&1){
                                int t=__gcd(a[x],a[y]);
                                int nt=(j^(1<<x)^(1<<y));
                                d[i+1][nt]=max(d[i+1][nt],d[i][j]+(i+1)*t);
                            }
                        }
                    }
                }
            }
        }
        return d[n/2][0];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值