• 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;
    }
     
  • 相关阅读:
    使用CAShapeLayer做出圆形的进度条 —— #DF!
    NSDate分类,把系统返回的时间与现在进行比较---秀清
    NSPredicate类,指定过滤器的条件---董鑫
    UITextFIeld的输入格式问题 ----W.P
    AttributeText创建多彩文字Label --- hl
    自定义简单动画
    Swift 学习网址精选 By HL
    【C++服务端技术】移动广播
    【C++服务端技术】定时器
    【面试攻略】C++面试-4399
  • 原文地址:https://www.cnblogs.com/lipu123/p/14151458.html
Copyright © 2020-2023  润新知