Codeforces Round #529 (Div. 3) C. Powers Of Two
http://codeforces.com/contest/1095/problem/C
题意:给n找出k个2的幂,加起来正好等于n。例如 9,4:9 = 1 + 2 + 2 + 4
思路:首先任何数都能表示成2的次幂的和,其次很容易发现,n和k都是二的次幂的情况是最基础的,因为可以分成k个n/k,而n/k一定是二的次幂。
所以,可以得出结论,只要n是2的次幂,且k<=n,一定有解。因为k一定能分成二的次幂的和。假如是 8,3就可以分成 4,1,、4,2这两种基础情况。
如果n不是2的次幂,那n也一定能分为,一个n以内最大的2的次幂加上另一个数,例如 36 = 32 + 4 、 63 = 32 + 31,由上可知,2的次幂是一定有解的,所以我们要给2的次幂尽量少分k,要给剩下的那个可能不是2的次幂的数多分k,好让那个数能够继续分成2的次幂和其他数的和。例如,63 = 32 + 31。32是一定有解得,31还要分成16 15 所以,要给31多分k。
1 #include <iostream> 2 #include <vector> 3 4 bool judge(int n){ 5 if((n > 0) && ((n & (n - 1)) == 0)) return 1; 6 return 0; 7 } 8 int find_near_power(int n){ 9 long long m = 1; 10 int cnt = 0; 11 while(m <= n){ 12 m = m * 2; 13 cnt++; 14 } 15 return 1 << (cnt - 1); 16 } 17 void dfs(int n, int k, std::vector<int> &res, int &ok){ 18 if(n == 0 && k == 0) return; 19 else if((n > 0 && k <= 0) || (k <= 0 && n > 0)) { 20 ok = 0; 21 return ; 22 } 23 24 if(n%2 == 1){ 25 k = k - 1; 26 res.push_back(1); 27 dfs(n-1, k, res, ok); 28 } else { 29 //std::cout << "n " << n << std::endl; 30 if(judge(n)){ 31 if(judge(k)){ 32 for(int i = 0; i < k; ++i){ 33 res.push_back(n/k); 34 } 35 } else { 36 int tmp = find_near_power(k); 37 dfs(n/2, tmp, res, ok); 38 dfs(n/2, k-tmp, res, ok); 39 //std::cout << "tmp " << tmp << std::endl; 40 } 41 } else { 42 int tmp = find_near_power(n); 43 //std::cout << "tmp " << tmp << std::endl; 44 if(n-tmp < k){ 45 dfs(tmp, k+tmp-n, res, ok); 46 dfs(n-tmp, n-tmp, res, ok); 47 } else { 48 dfs(tmp, 1, res, ok); 49 dfs(n-tmp, k-1, res, ok); 50 } 51 52 } 53 } 54 } 55 int main() 56 { 57 int n, k; 58 while(std::cin >> n >> k){ 59 if(n < k){ 60 std::cout << "NO" << std::endl; 61 continue; 62 } 63 int ok = 1; 64 std::vector<int> res; 65 dfs(n,k,res,ok); 66 if(ok == 1){ 67 std::cout << "YES" << std::endl; 68 for(int i = 0; i < k; ++ i){ 69 if(i == 0) std::cout << res[i]; 70 else std::cout << " " << res[i]; 71 } 72 std::cout << std::endl; 73 } else { 74 std::cout << "NO" << std::endl; 75 } 76 } 77 }