题解/算法 {2835. 使子序列的和等于目标的最少操作次数}

题解/算法 {2835. 使子序列的和等于目标的最少操作次数}

LINK: https://leetcode.cn/problems/minimum-operations-to-form-subsequence-with-target-sum/description/;

贪心题…

将T按照二进制拆分为[t1 < t2 < ... < tt], 从小到大遍历ti:
. @IF(ti等于 A A A里若干个数的和): 将 A A A里的这些数删除掉, 对答案不产生代价; (这是个贪心策略, 即从最小的 t i ti ti开始 而不是从大的);
. @ELSE: 必须从 A A A里找一个 > t i >ti >ti的数 a a a 然后对他进行分解, 这里非常非常重要 怎么对 a a a进行分解呢? 比如ti = 2, a = 16, 将他分解为[8, 4, 2, 2] 对答案的贡献是 3 3 3(16->8->4->2), 因为一个非常重要的性质 下一个ti是严格底层的 即t[i+1] > ti, 即所有的ti 都是不相同的, 因此 你不需要将他全部变成[2,2,2,2,...] 这样的话 会超时的 (比如ti=2, a = (1<<30));

int minOperations(vector<int>& A, int T){
    unordered_map< int, int> Mp; for( auto i : A) Mp[ i] ++;
    auto TryTo_eliminate = [&]( int _tar){
        auto Back = Mp;
        int t = _tar;
        while( true){
            while( _tar > 0 && Mp[ t] > 0){ -- Mp[ t], _tar -= t;}
            if( _tar == 0) break;
            if( t == 1) break;
            t /= 2;
        }
        if( _tar == 0){ return true;}
        Mp = move( Back);
        return false;
    };
    int ANS = 0;
    for( int i = 0; i <= 30; ++i){
        if( 0 == ((T >> i) & 1)){ continue;}
        int tar = (1 << i);
        if( TryTo_eliminate( tar)){ continue;}
        int cont = 0;
        bool succ = false;
        for( long long t = tar * 2LL; t <= (1LL << 30); t *= 2){
            ++ cont;
            if( Mp[ t] > 0){
                succ = true;
                Mp[ t] --;
                for( long long j = tar; j < t; j *= 2) Mp[ j] ++;
                ANS += cont;
                break;
            }
        }
        if( false == succ) return -1;
    }
    return ANS;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值