3次冪好數
阿新 • • 發佈:2020-12-17
給你一個正整數n。你真的很喜歡好的數字,所以你想找到最小的好數字大於或等於n。 如果正整數可以表示為3的不同冪的和(即不允許3的冪的重複),則稱為好整數。Input對於給定的正整數n,找到最小的m(n≤m),m是一個好數。Output輸入的第一行包含一個整數q(1≤q≤500)-查詢數。接下來是q查詢。 查詢的唯一一行包含一個整數n(1≤n≤10.....0(此處有18個0))。Example
Input8 1 2 6 13 14 3620 10000 1000000000000000000Output
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; } intmain(){ 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; }