2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest D:Distribution in Metagonia(构造)

本文介绍了一种算法,用于将一个给定的大数n拆分成多个形如2^p*3^q的数之和,且这些数之间不构成倍数关系。通过不断提取最大2的幂次和3的幂次来完成拆分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

      给你一个数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);  
    }  
} 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值