1. 程式人生 > 實用技巧 >3次冪好數

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",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\n",sum);
        }
    }
    return 0;
}