2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest.

D. Distribution in Metagonia

题面

image

题意

给你一个整数,要求你拆成这样的数的和:即每个数的质因子只能是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)\)

  1. 首先对于两个不能互相整除的数来说,乘上一个倍数并不会影响他们之间的关系。
  2. 由第一步可以知道,我们得到的k一定是一个既不能被2整除也不能被3整除的奇数,所以如果说我们将k减去一个3的x次幂,那么剩下的数字一定是偶数。那么这个剩下的数必然拥有至少一个2因子,而n作为3的x次幂,必然没有2因子。因此这二者一定不能互相整除。
  3. 现在我们考虑为什么 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;
}
posted @ 2022-04-27 15:54  _77  阅读(41)  评论(1编辑  收藏  举报