2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest.
D. Distribution in Metagonia
题面
题意
给你一个整数,要求你拆成这样的数的和:即每个数的质因子只能是2或者3, 且每个数之间不能互相整除。
思路
我们总是拆成 \((2^x* 3^y)* k\) 的形式,其中其中k显然是一个既不能被2整除也不能被3整除的奇数。对于这个k我们又可以拆解为 \((2^x* 3^y)* k\) 的形式,也就是目前是 \((2^x* 3^y)* (n + (2^p* 3^q)* s)\) 这样的形式,其中n是最接近k的3的最高次幂。由于s可能也需要拆解,所以我们需要递归求解。可以证明这样的形式一定满足题意。
粗略证明:要证明往后递归求解的正确性,我们可以先考虑这个公式的正确性:
\((2^x* 3^y)* (n + (2^p* 3^q)* s)\)
- 首先对于两个不能互相整除的数来说,乘上一个倍数并不会影响他们之间的关系。
- 由第一步可以知道,我们得到的k一定是一个既不能被2整除也不能被3整除的奇数,所以如果说我们将k减去一个3的x次幂,那么剩下的数字一定是偶数。那么这个剩下的数必然拥有至少一个2因子,而n作为3的x次幂,必然没有2因子。因此这二者一定不能互相整除。
- 现在我们考虑为什么 n是最接近k的3的最高次幂 才可行。如果n是最接近k的最高次幂,那么说明剩下的数一定不会有和n的幂数一样的质因子,也就是不会互相整除。若有,那么显然n的幂数就会+1。
代码
#include <bits/stdc++.h>
//#pragma comment(linker, "/STACK:102400000,102400000")//手动开大栈区
#define SF ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define ms(x, y) memset(x, y, sizeof(x))
#define INIT(ob, x, y, val) for(int i = x;i <= y;++i) ob[i] = val;
#define INF 0x3f3f3f3f
#define X first
#define Y second
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
vector<ll>ans;
void solve(ll n, ll m){
while(n%2 == 0) m*=2, n/=2;
while(n%3 == 0) m*=3, n/=3;
if(n == 1){
ans.push_back(m);
return ;
}
ll x = 3LL;
while(x*3 < n) x*=3;
n -= x;
ans.push_back(x*m);
solve(n, m);
}
int main(){
freopen("distribution.in", "r", stdin);
freopen("distribution.out", "w", stdout);
int t;scanf("%lld", &t);
while(t--){
ans.clear();
ll n;scanf("%lld", &n);
solve(n, 1);
printf("%d\n", ans.size());
for(auto x:ans){
printf("%lld ", x);
}
printf("\n");
}
return 0;
}