题目链接:http://codeforces.com/contest/1095/problem/C
题目大意:给你两个整数n和k,要求把n拆成k个2的幂的和。1 2 4 8 16…。如果无法做到就输出NO,能够做到就输出YES,并且输出k个2的幂加数。
思路:开始没有往二进制的方向想。只判断出是能不能满足条件。方案不知道怎么构造。
后来用了二进制。那么n的二进制有多少个1.这就是k的最小值。因为可以把高位的1拆成两个低进制的1。所以把所有高位的1的全部拆成最低位的1。就是k的最大取值。也就是n个2^0。
思考:因为后面的循环结束时没有判断所有的低位的和是否<k。所以第二天WA 29。-59。惨痛的教训。。。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int mod=1000000007;
char a[35];
int b[35];
int main()
{
int n, k, s=0;
scanf("%d%d",&n,&k);
if(k>n)
{
printf("NO\n");
return 0;
}
for(int i=0;i<32;i++)
{
a[i]=((n>>i)&1)+'0';
}
for(int i=32;i>=0;i--)
{
if(a[i-1]=='1')
{
n=i-1;
for(int j=i-1;j>=0;j--)
{
b[j]=a[j]-'0';
s+=b[j];
}
break;
}
}
if(k<s)
{
printf("NO\n");
return 0;
}
else
{
for(int i=n;i>=0;i--)
{
if(k>=s+b[i]&&i>0)
{
b[i-1]+=b[i]*2;
s+=b[i];
b[i]=0;
}
else if(k<s+b[i])
{
int m=k-s;
b[i-1]+=2*m;
b[i]-=m;
break;
}
else
{
printf("NO\n");
return 0;
}
}
printf("YES\n");
for(int i=0;i<=n;i++)
{
while(b[i]--)
{
printf("%d ",(int)pow(2, i));
}
}
}
return 0;