题目链接: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;