題目描述
趙老師做爲一個程序員,實在是太喜歡二進制了
以至於他十分喜歡2的次冪
他想要讓你幫他算出正整數n是否可以被分成k個2的某次冪之和
Input
第一行只有兩個正整數n,k (1 ≤ n ≤ 10^9 , 1 ≤ k ≤ 2· 10^5).
Output
如果不存在這樣的方案,輸出NO.
否則輸出YES,並且輸出 k個正整數,它們的和是n,如果有多種方案,輸出任意一種.
Examples
Input
9 4
Output
YES
1 2 2 4
Input
8 1
Output
YES
8
Input
5 1
Output
NO
Input
3 7
Output
NO
題目分析:
拿n=5,k=3舉例子,拆分成二進制爲(101),此時有兩個1,表示可以拆成至少兩份 爲 4+1,但是k=3,
根據性質 2n = 2n-1 * 2
我們可以將二進制(101)從最高位開始把 1 傳遞到下一位 (021) 這樣 拆分成了 2+ 2 +1 三份,
我們可以使用一個從大到小排列的優先隊列把4和1放入隊列中,依次取出最高位然後 把兩個最高位除以2 重新放入隊列中,知道滿足sum=k;
ACcode
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define gold_m main
using namespace std;
typedef long long ll;
const int N=1e6+10;
ll a[N];
int gold_m() {
ll n,k;
cin>>n>>k;
if(n==0&&k==0||k>n) {
cout<<"NO";
return 0;
}
ll cnt=1,sum=0;
priority_queue<ll,vector<ll>,less<ll>>heap;
while(n>0) {
if(n%2)
heap.push(n%2*cnt);
if(n%2) sum++;
cnt*=2;
n/=2;
}
if(sum>k) {
cout<<"NO";
return 0;
}
cout<<"YES"<<endl;
while(heap.size()<k) {
ll temp=heap.top();
heap.pop();
if(temp>=2) {
heap.push(temp/2);
heap.push(temp/2);
}
}
while(!heap.empty()) {
cout<<heap.top()<<" ";
heap.pop();
}
return 0;
}
另一種不使用STL的寫法
同樣的思路
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define gold_m main
using namespace std;
typedef long long ll;
const int N=1e6+10;
ll a[N];
int gold_m() {
ll n,k;
cin>>n>>k;
if(n==0&&k==0||k>n) {
cout<<"NO";
return 0;
}
ll cnt=0,sum=0;
while(n>0) {
a[++cnt]=n%2;
if(n%2) sum++;
n/=2;
}
ll t= cnt;
// 從高位cnt開始
while(sum<k) {
if(cnt==1)
break;
if(a[cnt]) {
a[cnt]--;
a[cnt-1]+=2;
} else {
cnt--;
}
if(a[cnt])
sum++;
}
if(sum!=k) {
cout<<"NO";
return 0;
}
cout<<"YES"<<endl;
ll temp=1;
for(int i=1 ; i<=t; i++) {
for(int j=1; j<=a[i]; j++)
cout<<temp<<" ";
temp*=2;
}
return 0;
}