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;
}