3次幂好数

传送门

给你一个正整数n。你真的很喜欢好的数字,所以你想找到最小的好数字大于或等于n。 如果正整数可以表示为3的不同幂的和(即不允许3的幂的重复),则称为好整数。Input对于给定的正整数n,找到最小的m(n≤m),m是一个好数。Output输入的第一行包含一个整数q(1≤q≤500)-查询数。接下来是q查询。 查询的唯一一行包含一个整数n(1≤n≤10.....0(此处有18个0))。Example

Input
8
1
2
6
13
14
3620
10000
1000000000000000000
Output
1
3
9
13
27
6561
19683
1350851717672992089


这个题有两个解法
1.贪心法
注意到,我们可以先令 m = ∑ 3 ^ i ,求出此时满足条件的最小的m,随后,
因为m在三进制下,每一位都是1,那么如果我们从高位开始,不断地判断 m - 3 ^ i >= n ,
如果满足,则令 m -= 3 ^ i ,此时我们删除了当前可以删除的最大数,这样将使得最终的结果最小,并且大于等于n
(意思就是先找一个最小的满足条件的,然后再倒着减)
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=3e6+100;
ll qpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            ans=(ans*a);
        }
        a=a*a;
        b/=2;
    }
    return ans;
}
int main(){
    int t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        ll cnt=0;
        ll ans=0;
        while(ans<=n){
            ans+=qpow(3ll,cnt);
            cnt++; 
        }
        for(int i=cnt;i>=0;i--){
            if(ans-qpow(3ll,i)>=n){
                ans-=qpow(3ll,i);
            }
        }
        cout<<ans<<endl;
    }
}
 

2.类比二进制,转化为三进制+思维(有待研究)

将n用三进制表示出来,分析可得只有0和1时,这样的数才符合题意。
可以从高位开始遍历(保持它最小),找到第一个3进制位为2的(如果没有则表示这个数本身就是符合要求的数)。
拿14来说它的3进制数是112,从高位到低位第三位为2,记录2所在的位置,从该标记位到高位遍历,为2则向高位进1,最后变为1000
#include<cstdio>
#include<cstring>
typedef long long LL;
int a[200],k;
void init()
{
    memset(a,0,sizeof(a));
    k=0;
}
void solve(LL m)
{
    while(m)
    {
        a[k++]=m%3;
        m/=3;
    }
}
LL quick(LL x,LL nn)/*pow函数是求浮点数的,会造成精度损失,最好是用快速幂*/
{
    LL res=1;
    while(nn)
    {
        if(nn&1)
            res=res*x;
        x=x*x;
        nn>>=1;
    }
    return res;
}
int main()
{
    int T;
    LL n;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%lld",&n);
        solve(n);

        int lab,flag=0;
        for(int i=k-1; i>=0; i--)
        {
            if(a[i]==2)
            {
                lab=i;/*从高位到低位找到第一个2的位置*/
                flag=1;
                break;
            }
        }

        if(!flag)
            printf("%lld
",n);
        else
        {
            LL sum=0;
            for(int i=lab; i<k; i++)
            {
                if(a[i]==2)
                {
                    a[i]=0;
                    a[i+1]++;
                }
            }
            if(a[k])
                k++;

            for(int i=k-1; i>=lab; i--)
            {
                sum+=a[i]*quick(3,i);
            }
            printf("%lld
",sum);
        }
    }
    return 0;
}
 
原文地址:https://www.cnblogs.com/lipu123/p/14151458.html