在數據結構課關於棧的這一章中,咱們都學過用「模2取餘法」來將一個10進制數轉換爲一個二進制數,進而能夠推廣到「模n取餘法」,經其轉換爲n進制(n任意指定)。確實,這是一個很基礎的題目,可你是否想過若是這個10進制數是一個大數(其位數可能上千位,此時用通常數據類型確定是會溢出的),那麼這個問題又如何來求解呢?c++
固然,也許你會說很簡單嘛,本身寫一個大數類(固然至少要寫一個大數除法才行),或者你用的是Java這種現代化語言,就更輕鬆了,直接用BigInteger這樣的大數類就能夠來表示一個大數,進而用書上教的方法來實現。算法
可是,真的須要用到大數類嗎?事實上,「殺雞焉用牛刀「,咱們在紙上模擬一番上述運算後就能夠發現,只要作一些小小的改進,就能夠在不使用大數的狀況下,也能夠經過「模n數組
取餘」的原理來實現大數的進制轉換的。(固然,總體的思想仍然是「模n取餘」原理!!!)。數據結構
舉個簡單的例子,就好比說把10進制數12轉換爲2進制形式,書上的方法能夠用下圖來表示spa
按照 「先餘爲低位,後餘爲高位「這條鐵律,其結果爲1100..net
這是書上教咱們的常規思路(惋惜按這個的話,大數是無法考慮的,由於假如這裏不是12,而是一個1000位的大數,因爲是是對大數的總體進行取餘運算,不使用大數類及其設計
除法操做,又如何得以進行呢?),可咱們的目的是不使用大數類,那麼如今咱們就來換一個視角來看這個問題,12是一個十位數,十位上是1,個位上是2,按照咱們正常的code
思惟來看,這個計算應該是下面這樣的:blog
那麼咱們發如今第一輪運算時,十位上的1做爲被除數,2做爲除數,獲得的商是0,餘數是1(能夠斷言只考慮當前這一個數位的計算,餘數或是0,或是1,如果1的話,則進ci
下一數位(這裏即對個位進行運算)時,要用1乘上進制(這裏是10)再加上下一個數位上的值(這裏是2)),即獲得運算進入個位時被除數是12,除數是2,獲得的商是6,
數是0。第一輪運算的結果是商是06,餘數是0.
進入第二輪運算,則上一輪的商6(這裏首先要去掉前面多餘的0)變成本輪的被除數,如此下去,便可獲得每輪的餘數。
推廣開來,若是被除數是一個1000位的大數,例如「12343435154324123……342314324343」
那麼咱們照樣能夠從第一個數位開始逐位考慮,好比第一位是1(做爲被除數),2是除數,獲得的商是0,餘數是1,而後是第二個數位2,因爲上一位留下了餘數1,則此時被
除數應該是1*10+2 = 12,因此獲得的商是6,餘數是0,即運算到此時的商是06,而後是第三個數位3,因爲上一個數位留下的餘數是0,因此此時被除數就是3,。。。如此下去
就完成第一輪的運算,這一輪完畢後,須要把獲得的商變成下一輪的被除數,繼續上述的運算,直到被除數爲0才中止。
下面給出了一個示例代碼,展現瞭如何將一個10進制的大數轉換爲其二進制形式,僅供參考:
1 #include <stdio.h> 2 #include <string.h> 3 4 char str[1000];//輸入字符串 5 int start[1000],ans[1000],res[1000]; //被除數,商,餘數 6 7 //轉換先後的進制 8 const int oldBase = 10; 9 const int newBase = 2; 10 11 void change() 12 {//各個數位還原爲數字形式 13 int i,len = strlen(str); 14 start[0] = len; 15 for(i=1;i<= len;i++) 16 { 17 if(str[i-1] >= '0' && str[i-1] <= '9') 18 { 19 start[i] = str[i-1] - '0'; 20 } 21 } 22 } 23 24 void solve() 25 { 26 memset(res,0,sizeof(res));//餘數初始化爲空 27 int y,i,j; 28 //模n取餘法,(整體規律是先餘爲低位,後餘爲高位) 29 while(start[0] >= 1) 30 {//只要被除數仍然大於等於1,那就繼續「模2取餘」 31 y=0; 32 i=1; 33 ans[0]=start[0]; 34 // 35 while(i <= start[0]) 36 { 37 y = y * oldBase + start[i]; 38 ans[i++] = y/newBase; 39 y %= newBase; 40 } 41 res[++res[0]] = y;//這一輪運算獲得的餘數 42 i = 1; 43 //找到下一輪商的起始處 44 while((i<=ans[0]) && (ans[i]==0)) i++; 45 //清除這一輪使用的被除數 46 memset(start,0,sizeof(start)); 47 //本輪獲得的商變爲下一輪的被除數 48 for(j = i;j <= ans[0];j++) 49 start[++start[0]] = ans[j]; 50 memset(ans,0,sizeof(ans)); //清除這一輪的商,爲下一輪運算作準備 51 } 52 } 53 54 void output() 55 {//從高位到低位逆序輸出 56 int i; 57 for(i = res[0];i >= 1;--i) 58 { 59 printf("%d",res[i]); 60 } 61 printf("\n"); 62 } 63 64 int main() 65 { 66 scanf("%s",str); 67 change(); 68 solve(); 69 output(); 70 return 0; 71 }
接下來讓咱們將次算法具體應用到題目中:
題目地址:https://ac.nowcoder.com/acm/contest/910/C
第一行一個整數T,表明有T組數據
接下來T行:
每一行有3個整數,分別表示m,n,a,其中2=<m<=62,2=<n<=62,a的位數不超過350位且a>=0,樣例個數不超過400。
輸出上述問題的答案,每一個答案佔一行。
1 10 2 3
11
hashch[]與hashnum這兩個數組我以爲設計的很是好!
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=5000+100; 4 char hashch[maxn]; 5 int hashnum[maxn]; 6 void init() 7 { 8 char ch; 9 for(int i=0;i<62;i++){ 10 if(i<10) ch=i+'0'; 11 else if(i>=10&&i<36) ch='A'+i-10; 12 else ch='a'+i-36; 13 hashch[i]=ch; 14 hashnum[ch]=i; 15 } 16 } 17 string change(int m,int n,string str) 18 { 19 bool flag; 20 string ans=""; 21 int tmp,quotient,remainder; 22 while(true) 23 { 24 flag=false; 25 remainder=0; 26 string div=""; 27 int len=str.length(); 28 for(int i=0;i<len;i++){ 29 tmp=remainder*m+hashnum[str[i]]; 30 quotient=tmp/n; 31 remainder=tmp%n; 32 if(flag){ 33 div+=hashch[quotient]; 34 } 35 else{ 36 if(quotient!=0){ 37 flag=true; 38 div+=hashch[quotient]; 39 } 40 } 41 } 42 ans=hashch[remainder]+ans; 43 str=div; 44 if(flag==false) break; 45 } 46 return ans; 47 } 48 49 int main() 50 { 51 init(); 52 int t; 53 scanf("%d",&t); 54 while(t--){ 55 int m,n; 56 string str; 57 cin>>m>>n>>str; 58 string ans=change(m,n,str); 59 cout<<ans<<endl; 60 } 61 return 0; 62 }
參考文獻: