Sicily 1295 負權數 (SOJ 1295) 【進制轉換】

20130619.後來我在網上漫看Matrix67的博客,發現了這篇專門講述進制轉換的,“好嘢大家摞出來分享”,可以先參看Matrix67《漫話進位置》


原題地址:點擊打開鏈接

這題是目前我見過最難的(對於我來說)進制轉換題,當然對於一些大牛來說想必思路是十分的清晰,可是對於鄙人是十分困難。做題思路是問了周生然後才寫出來的,通過的人數比較多````莫非是水題行列之一?咳咳,不管怎麼說,做這到題對於我的提升還是非常大的,建議各位也思考一下。

看到一個比較神的解法,鏈接在此:點擊打開鏈接

但是我看不懂這個解法的原理……所以我還是用我理解的解法來說好了。

——————正文——————

類比一下正常的進制情況下如何表示一個數?其實就是用進制的不同次冪配上係數,然後組合起來。

說得更本質一點,就是我們要從高位開始“試錯”,看看在當前這個位所能表示的範圍有沒有包含所要求的數,例如:

對於3進制的數,如何表示十進制的10?

1 首先我們試一下只有1位的情況下,能不能表示,1位的情況,最小是0,最大是2,顯然10不在[0,2]這個範圍內,1位無法表示

2 然後試一下有2位的情況,這種情況下,最小是0,最大是2*3^1+2*3^0=8,可見10不在[0,8]範圍內,2位無法表示

3 然後是一下3位的情況,這樣子,最小是0,最大是2*3^2+2*3^1+2*3^0=26,10在[0,26]範圍內,因此在3進制中,3位就必定可以表示十進制中的10

然後從高位往回推,在第三位應該填的數字是多少?假設填k(在3進制下,k必定小於3),那麼k必須滿足(10-k*3^2)<=2*3^1+2*3^0

為什麼呢?填了第3位後,剩下的數是10-k*3^2,如果這個時候不滿足上面的不等式,那麼剩下的兩位是無法繼續表示這個剩餘數的。

取k=1,即第3位添1,那麼剩下10-1*3^2=1;

看看第二位,假設第二位填k1,因爲1<=2*3^0成立,所以k1填0即可,第2位位0

最後一位很簡單了,直接填1就可以了,所以10在3進制中表示就是101.


我相信上面的敘述沒有結束,肯定有人就知道這題的思路是怎麼樣了,沒錯,從地位開始計算,每增加一位,求出當前位置可以表示出的範圍,然後看看要求的n是否在這個範圍內即可,原理和上面一模一樣。同時介紹一下sscanf(不是scanf)這個函數,非常好用,可以自己查下使用方法,或者直接看下面的註釋

那就直接上代碼了,如下:

#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<memory.h>
#define MAXX 32770
using namespace std;
char s[50];           //字符串用於讀取輸入
int a[50];            //保存結果
int n,r;
int mp[17][32][3];    //mp[i][j][0]表示-i進制下其j次冪是多少
                      //mp[i][j][1]表示-i進制下到第j位可表示的最小數
					  //mp[i][j][2]表示-i進制下到第j位可表示的最大數

bool outside(int index) //到第index位還是不能表示則返回true,否則false
{
	if(mp[-r][index][1]>n || mp[-r][index][2]<n)
	 return true;
	return false;
}
char cv(int digit)
{
	if(digit<10)
	 return '0'+digit;
	else
	 return 'A'+digit-10;
}
int main()
{
    //freopen("in","r",stdin);
    //freopen("out","w",stdout);
    for(int i=-2;i>=-16;--i)
    { 
      int j=0;
      int mu=-i-1;
      mp[-i][j][0]=1;
      mp[-i][j][1]=0;
      mp[-i][j][2]=mu;
      while(abs(mp[-i][j][0])<=MAXX)
      {
        j++;
        mp[-i][j][0]=mp[-i][j-1][0]*i;
        if(mp[-i][j][0]>0)
        {
          mp[-i][j][1]=mp[-i][j-1][1];
          mp[-i][j][2]=mp[-i][j-1][2]+mp[-i][j][0]*mu;
        }
        else
        {
          mp[-i][j][1]=mp[-i][j-1][1]+mp[-i][j][0]*mu;
          mp[-i][j][2]=mp[-i][j-1][2]; 
        }
      }
    }//預處理完畢,不是必要的,但是測試數據多時跑起來會快一點
    while(scanf("%s",s)!=EOF)
    {
      if(s[0]=='#')
       break;
      sscanf(s,"%d",&n); //這是個非常方便的函數
						 //直接將字符串內容作爲輸入
						 //尤其適合於字符串轉數字
      scanf("%d",&r);
      int i=0;
      memset(a,0,sizeof(a));
      while(mp[-r][i][1]>n || mp[-r][i][2]<n)
        i++;
      for(;i>=1;i--)
      {
		 a[i]=0;
         while(outside(i-1))
		 {
			n-=mp[-r][i][0];
			a[i]++;
		 }
      }
      a[0]=n;
      i=31;
      while(a[i]==0) i--;
      if(i<0) i=0;
      for(;i>=0;--i)
		printf("%c",cv(a[i]));
      printf("\n");
    }
}


******<轉載說明>******
轉載註明:誠實的偷包賊
原文地址:http://blog.csdn.net/fanfank/article/details/8983754
******<轉載說明/>******

















發佈了61 篇原創文章 · 獲贊 1 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章