题意:
给你一个数n([1,1e18])让你把n拆成若干个数之和的形式,使得这些数都是2^p*3^q形式,因子中只有2和3,而且相互之间不是倍数关系。
输出拆分的个数,以及拆分的数。
分析:
1. 先提取最大的2^i,减去
2.在减去最大3^j,又得到偶数
如此反复能得到每个数,3^j j是递减的 2^i i 是递增的 这样就可以保证相互之间不是倍数关系。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 1e4+10;
const ll INF = 1e18;
const int MOD = 1e9+7;
const double EPS = 1e-10;
const double Pi = acos(-1.0);
vector<ll> ans;
int main(){
#ifdef LOCAL
freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
//freopen("output.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
//freopen("distribution.in","r",stdin);
//freopen("distribution.out","w",stdout);
int T;
cin>>T;
while(T--)
{
ans.clear();
ll n;
cin>>n;
while(n)
{
ll temp = 1, m = n;
while(m % 2 == 0) temp *= 2, m /= 2;
// cout<<temp<<" ";
while(temp * 3 <= n) temp *= 3;
ans.push_back(temp);
n -= temp;
}
// cout<<endl;
cout<<ans.size()<<endl;
for(int i = 0; i < ans.size(); i++)
if (i == 0) cout<<ans[i];
else cout<<" "<<ans[i];
cout<<endl;
}
return 0;
}
感觉另一种构造好理解些,本质似乎是一样的。
以下他人博客引用:
第一步:因为要求的 m 是 2^x * 3^y 的形式,所以如果 n 可以直接被 2^x * 3^y 整除的话,即 n % (2^x * 3^y) == 0,那么就可以直接输出 n 了。如果不能被直接整除的话,我们可以先将 n 拆解成不能被 3 和 2 整除的形式。
第二步:那么更重要的问题是如果 n 不能被 2 或 3 整除,同时也不为 1 时应该怎么做。因为不能被 2 整除,所以这时的 n 必定是一个奇数。那么我们可以将 n 减去 w,w = 3^y && w < n,我们所做的是将 n 拆解出一个 w(w必定为奇数),那么剩下的 n 就是一个偶数了,这个时候我们又能回到第一步进行递归求解了。
xx(xx+xx(xx+...)) 大概就是把这个数变成这样的式子, 然后拆开就是答案。
void solve(LL n,LL mul)
{
while(n%2==0)
{
n/=2;
mul*=2;
}
while(n%3==0)
{
n/=3;
mul*=3;
}
if(n==1)a[++m]=mul;
else
{
LL x;for(x=3;x*3<n;x*=3);
a[++m]=mul*x;
solve(n-x,mul);
}
}