題解:CF437B The Child and Set

Night_Tide發表於2024-09-26

CF437B The Child and Set 題解

這題目就一個問題。

啥是 \(\operatorname {lowbit}\)

\(\operatorname {lowbit}(x)\) 是指 \(x\) 的二進位制表示中最低位的 \(1\) 所表示的值。

例如 \((14)_{10} = (1110)_2\),其中最低位的 \(1\) 在第二位,表示 \((2)_{10}\),即 \(\operatorname {lowbit}(14) = 2\)

接下來考慮如何選取。

一個貪心策略是按照 \(\operatorname {lowbit}\) 從大到小選取,如果當前的數的 \(\operatorname {lowbit}\) 小於剩餘的 \(n\),那麼就選到這個數,並讓 \(n\) 減去當前數的 \(\operatorname {lowbit}\)

顯而易見這樣取出來的總和最大。

如果取到最後還不能取完,那麼就輸出 -1

有點類似於倍增。

至於怎麼求 \(\operatorname {lowbit}\),先人給我們找好了方法:

\[\operatorname {lowbit}(x) = x\; \& \;(-x) \]

這是利用計算機補碼性質完成的,其中的符號 \(\&\) 代表按位與。

最終程式碼如下:

#include<bits/stdc++.h>
#define MAXM 100010
using namespace std;
struct node{
    int num, bit;
};
bool operator < (node a, node b){ return a.bit < b.bit; }
bool operator > (node a, node b){ return a.bit > b.bit; }
node a[MAXM];
int n, m;
vector<int> ans;
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= m; i++) a[i] = (node){i, i & (-i)};
    sort(a + 1, a + m + 1, greater<node>());
    for(int i = 1; i <= m && n >= 0; i++){
        if(n >= a[i].bit){
            n -= a[i].bit;
            ans.push_back(a[i].num);
        }
    }
    if(n != 0) printf("-1\n");
    else{
        printf("%ld\n",ans.size());
        for(int i = 0; i < ans.size(); i++) printf("%d ",ans[i]);
        printf("\n");
    }
    return 0;
}

相關文章