http://codeforces.com/gym/100801/attachments
题意:给出一个数n(1 <= n <= 1e18),将 n 拆成 m 个整数,其中 m 必须是 2^x * 3^y 的形式,并且 x 和 y 不能被彼此整除, 输出 m 并将这些整数输出。
思路:Inspired by http://blog.csdn.net/snowy_smile/article/details/49852091 。
第一步:因为要求的 m 是 2^x * 3^y 的形式,所以如果 n 可以直接被 2^x * 3^y 整除的话,即 n % (2^x * 3^y) == 0,那么就可以直接输出 n 了。如果不能被直接整除的话,我们可以先将 n 拆解成不能被 3 和 2 整除的形式,这里的话用一个 mul 记录 n 除以多少。
1 while(n % 3 == 0) { 2 n /= 3; 3 mul *= 3; 4 } 5 while(n % 2 == 0) { 6 n /= 2; 7 mul *= 2; 8 } 9 if(n == 1) { 10 num[m++] = mul; 11 return ; 12 }
第二步:那么更重要的问题是如果 n 不能被 2 或 3 整除,同时也不为 1 时应该怎么做。因为不能被 2 整除,所以这时的 n 必定是一个奇数。那么我们可以将 n 减去 w,w = 3^y && w < n,我们所做的是将 n 拆解出一个 w(w必定为奇数),那么剩下的 n 就是一个偶数了,这个时候我们又能回到第一步进行递归求解了。因为我们拆出的 w 也是组成 n 的一部分,因此要记录下来,记录的数值是 w * mul,因为我们前面 n 除以了 一些 2 和 3 ,我们用 mul 记录下来了,因此这个时候要乘回去,所以是 w * mul。
1 else { 2 long long x = 3; 3 while(x * 3 < n) { 4 x *= 3; 5 } 6 n -= x; 7 num[m++] = x * mul; 8 solve(n, mul); 9 }
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #include <map> 8 #include <cstdlib> 9 using namespace std; 10 typedef long long LL; 11 LL num[150]; 12 int m; 13 /* 14 题意:将n拆成m个数,这m个数的表示是 15 */ 16 void solve(LL n, LL mul) 17 { 18 while(n % 3 == 0) { 19 n /= 3; 20 mul *= 3; 21 } 22 while(n % 2 == 0) { 23 n /= 2; 24 mul *= 2; 25 } 26 if(n == 1) { 27 num[m++] = mul; 28 return ; 29 } else { 30 long long x = 3; 31 while(x * 3 < n) { 32 x *= 3; 33 } 34 n -= x; 35 num[m++] = x * mul; 36 solve(n, mul); 37 } 38 } 39 40 int main() 41 { 42 freopen("distribution.in", "r", stdin); 43 freopen("distribution.out", "w", stdout); 44 int t; 45 cin >> t; 46 while(t--) { 47 LL n; 48 cin >> n; 49 m = 0; 50 solve(n, 1); 51 cout << m << endl; 52 for(int i = 0; i < m; i++) { 53 cout << num[i]; 54 if(i != m-1) cout << " "; 55 else cout << endl; 56 } 57 } 58 return 0; 59 }