SPOJ tutorial 429 Simple Numbers Conversion 解题报告

题目来源: https://www.spoj.pl/problems/TCONNUM/

429. Simple Numbers Conversion

Problem code: TCONNUM

Every integer number n is represented in positional number system of base r by a sequence of digits 0 <= di, so the value is equal to:

n = d 0 + r * d 1 + r 2 * d 2 + r 3 * d 3 + ...

Your task is to convert a given number in r-base represantation into s-base representation, for example: decimal 231 into binary 11100111. Assume that r <= 36 and the digits are 0,1,2,3,4,5,6,7,8,9, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z.

Input

N [the number of series <= 1000]
n r s [n <= 101000, r,s <= 36]

Output

n [s-base representation of number n]

Text grouped in [ ] does not appear in the input and output file.

Example

Input:
3
231 10 2
ABC 15 10
XYZ 36 2

Output:
11100111
2427
1010101111111011

Added by: Michał Małafiejski
Date: 2004-10-13
Time limit: 12s
Source limit: 5000B
Languages: C C++ PAS gpc PAS fpc






》》》》》》》》》》》》》》》》》》 我是分割线 》》》》》》》》》》》》》》》》》》》

题目的意思就是将 r 进制的数字 n 转换成 s 进制并输出。 r , s <= 36 ,  n <= 10 1000

r  进制数的每一位用一个小于 r 的十进制整数表示。0, 1,2,,,9,A, B,C,,,Z 分别用 0,1,2,,,9,10,11,12,,,35 表示。

先从最基本的二进制和十进制的互相转换考虑。
十进制数 n 转成二进制数只要不断用 2 来除以 n ,余数作为结果的较低位,直至 n 被除成 0 。需要用到大整数除法,而除数不是大整数。
二进制数 n 转成十进制可以用 n 的各位数字乘以该位的权,累加即可。这样需要用到大整数乘法,而乘数不是大整数。(但是效率看起来很低的样子,因为如果 n 是 二进制的,那么至少有 3000 位吧!不过时间有 12S 。)
那么完全可以用大整数来做,某人就是用 JAVA 的大整数类来做的,但是提交的时候才发现测试系统在这道题上不接受 JAVA ,令某人失望啊! 我想这道题如果就是用别人的成品来做也没什么意思,应该有其他方法的。

要自己用 C++ 来实现大整数的运算吗?
我想即使实现了效率也不够高。

还是先从 r >= s 的情况考虑吧, r = s 时就不用转换啦。
r > s 时,如果将 n 转成 10 进制,再转成 s 进制,那么太浪费时间了。干脆用十进制转二进制的方法来做。那么这样要求用到 r 进制的除法了,由于各位数字是用 10 进制数字来表示的,那么就可以用 10 进制除法来模拟 r 进制除法了。
举例如下:
15 进制的 ABC (10'11'12)转换成 10 进制

10 /    10        11        12
         余0
---------------------------------
                      0*15
      + 商1        11        12
---------------------------------
10/        1        11        12
                      余1
---------------------------------
                                  1*15
      +     1       商1        12
---------------------------------
10/        1           1        27
                                   余7-------作为结果的第 0 位
===================
10/        1           1       商2
           余1
---------------------------------
                        1*15
      +   商0         1          2
---------------------------------
10/          0      16          2
                      余6
---------------------------------
                                  6*15
      +       0     商1         2
---------------------------------
10/          0         1       92
                                   余2-------作为结果的第 1 位
===================
10/          0         1      商9
            余1
---------------------------------
                                  1*15
    +         0       商0       9
---------------------------------
10/          0          0      24
                                  余4------作为结果的第 2 位
==================
10/          0          0    商2
                                  余2------作为结果的第 3 位
==================
               0           0   商0------已经除尽,终止


因此 15 进制的 ABC 转换成 10 进制的 2427 。

那么当 r < s 时怎么办?很快我发现很容易就可以把 r 进制数 n 转换成 r 2 , r 3 。。。 进制,例如 二进制的 1010 0001 转换成 十六进制的 A1。
那么将 r 转换成 t 进制, t >= s 即可使用除法来将 t 进制转换成 s 进制了。

代码如下:

#include  < iostream >
#include 
<string>
#include 
< vector >
using   namespace  std;

int  char2int ( char  ch)
{
    
return ((ch >= 'A'? (ch - 'A' + 10) : (ch - '0'));
}


char  int2char ( int  i)
{
    
return ((i >= 10? (i - 10 + 'A') : (i + '0'));
}


vector 
< int >  string2longint ( string  s)
{
    
int size = s.size ();
    vector 
<int> li(size);
    
int i, j;
    
for (i = 0, j = size - 1; i < size; i ++, j --)
    
{
        li [i] 
= char2int (s [j]);
    }

    
return li;
}


string  longint2string (vector  < int >  li,  int  len  =   - 1 )
{
    
// 截取大整数 li 的后面 len 位并转换为字符串 s , len 越界则截取全部
    int size = li.size ();
    size 
= ((len < 0 || len > size) ? size : len);
    
string s (size, ' ');
    
int i, j;
    
for (i = 0, j = size - 1; i < size; i ++, j --)
    
{
        s [i] 
= int2char (li [j]);
    }

    
return s;
}


vector 
< int >  ChangeBase (vector  < int >  li,  int  r,  int  s)
{
    
// change long int li's base r to s
    vector <int> ret;
    
int size = li.size ();
    
if (size <= 0)
    
{
        
return ret;
    }

    
if (r < s)
    
{
        
// 扩展为 t 进制, t >= s
        int rr [10= {1, };
        
int c = 1;
        
int t = r;
        
while (t < s)
        
{
            rr [c] 
= t;
            t 
*= r;
            c 
++;
        }

        
int p = 0;
        
int i, j, cx;
        
for (i = 0; i < size - c; i += c)
        
{
            cx 
= 0;
            
for (j = 0; j < c; j ++)
            
{
                cx 
+= li [i + j] * rr [j];
            }

            li [p 
++= cx;
        }

        
for (j = 0, cx = 0; i < size; i ++, j ++)
        
{
            cx 
+= li [i] * rr [j];            
        }

        li [p 
++= cx;
        size 
= p;
        r 
= t;
    }

    
int i, j, k = size - 1;    // j 为余数, k 为最高位
    if (r == s)
    
{
        
for (i = 0; i < size; i ++)
        
{
            ret.push_back (li [i]);
        }

        
return ret;
    }

    
while (k >= 0)
    
{
        j 
= 0;
        
for (i = k; i >= 0; i --)
        
{
            li [i] 
+= j * r;
            j 
=  li [i] % s;
            li [i] 
/= s;
        }

        ret.push_back (j);
        
while (k >= 0 && li [k] == 0)
        
{
            k 
--;
        }

    }

    
return ret;
}


int  main ()
{
    
string ss;
    
int t, r, s;
    cin 
>> t;
    
while (t --)
    
{
        cin 
>> ss >> r >> s;
        vector 
<int> li = string2longint (ss);
        vector 
<int> cb = ChangeBase (li, r, s);
        ss 
= longint2string (cb, -1);
        cout 
<< ss << endl;
    }

    
return 0;
}


提交后的运行结果:
ID     DATE     USER    PROBLEM    RESULT     TIME     MEM     LANG
968772     2007-08-10 17:49:52     rappizit    Simple Numbers Conversion    accepted     6.79     2716     C++
6.79秒,不是很快。其实我为了方便以后可以重用,就用了STL 来做,效率应该因此而降低了吧?调用参数时引用调用会快些吧?hmhm。。
PS:
好久没写日志了,最近都在做题 ^_^
这道题可是一次提交就 AC 了的,爽!而且我是第 98 个 AC 的人。o(∩_∩)o...还有昨天夜里做的 Prime Generator 一题,也是一次就 AC 的,太爽了。使用筛法来筛出 1000000000 以内的一个长度不超过 100000 的范围段内的所有素数,如果直接用筛法来做,那么需要用上成 G 的内存!采用分段筛选 OK 。。而且效率挺高的,时间只用了 0.04 S 。o(∩_∩)o...

ID     DATE     USER    PROBLEM    RESULT     TIME     MEM     LANG
968053     2007-08-09 21:12:09     rappizit    Prime Generator    accepted     0.04     2708     C++

你可能感兴趣的:(C++,vector,String,generator,output,Numbers)