OpenJudge NOI 1.13 44:正整数的任意进制转换

【题目链接】

OpenJudge NOI 1.13 44:正整数的任意进制转换
注意:题目说是正整数的进制转换,而实际上输入的数字可能有0。

【题目考点】

1. 数制

2. 高精度

【解题思路】

先处理字符串,将输入的字符串拆分成p,p进制字符串n,及q。

遍历字符串,遇到逗号时,截取一段字符串。将截取出的第一和第三段字符串转为整数,就是p与q,第二段字符串为数字串。

先考虑如果涉及的都是低精度数字,应该如何将p进制的n转为q进制。
先将p进制的n转为值v,再对v在q进制下做数字拆分,得到q进制下的数字串。

#include<bits/stdc++.h>
using namespace std;
int p, q;
string n; 
void parse(string s)//解析输入的字符串s 
{
    
    
    string t;
    int c = 0;//记录上个逗号的位置 
    for(int i = 0; i < s.length(); ++i)
    {
    
    
        if(s[i] == ',')
        {
    
    
            if(c == 0)//如果是第一个逗号
            {
    
    
                t = s.substr(0, i);//从0开始取i个
                p = stoi(t);//这个子串为第一个进制数字      
                c = i;
            }
            else//如果是第二个逗号 
            {
    
    
                n = s.substr(c+1, i-c-1);//c是上一个逗号的位置,数字串第一个字符的位置为c+1,此时第二个逗号位置为i,数字串长度为i-c-1 
                t = s.substr(i+1);//从i+1到末尾为第二个进制数字
                q = stoi(t);
                break; 
            }
        }
    }
}
int getVal(char c)//字符转数值 
{
    
    
    if(c >= '0' && c <= '9')
        return c-'0';
    else
        return c-'A'+10;
}
char getCh(int n)//数值转字符 
{
    
    
    if(n >= 10)
        return n-10+'A';
    else
        return n+'0';
}
int toVal(string n)
{
    
    
    int num = 0;
    for(int i = 0; i < n.length(); ++i)
        num = num*p + getVal(n[i]);
    return num;
}
string toStr(int v)
{
    
    
    string r;
    int a = v;
    while(a > 0)//q进制下的数字拆分 
    {
    
    
        r = getCh(a%q) + r;   
        a /= q;
    }
    return r;
}
int main()
{
    
    
    string s;
    cin >> s;
    parse(s);
    int v = toVal(n);
    cout << toStr(v);
    return 0;
}

以上代码可以解决数值在int类型范围内的数字的数制转换。
而本题n可以达到50位,必须用高精度数字表示。
将输入的数字串转为p进制高精度数字。
上述代码中“将p进制数字转为值”这一步不用做了,因为不存在可以表示这个值的基本数据类型。
直接将p进制高精度数字,转为q进制高精度数字,其逻辑与toStr函数的逻辑是相同的。
先让高精度数字a的值为p进制高精度数字n的值。只要a不为0,每次让a除以q(高精除低精),得到余数r(低精度)作为q进制数字串的一位,将得到的商再赋值给a。循环执行,直到a为0。这样就得到了q进制字符串。
注意:数字拆分写法for(int a = n; a > 0; a /= 10)只能在n大于0时才能使用。这里的高精度数字n仍然可能是等于0的(虽然题目说了“正整数”,但实际数据中存在0),因此对于数字n是0的情况要做特判。
考虑极端情况如果36进制数字“50位Z”转为二进制数字,得到的数字位数可以达到300位。

【题解代码】

解法1:使用数字数组

#include<bits/stdc++.h>
using namespace std;
#define N 55
int p, q;
string n; 
void parse(string s)//解析输入的字符串s,得到p,q,n 
{
    
    
    string t;
    int c = 0;//记录上个逗号的位置 
    for(int i = 0; i < s.length(); ++i)
    {
    
    
        if(s[i] == ',')
        {
    
    
            if(c == 0)//如果是第一个逗号
            {
    
    
                t = s.substr(0, i);//从0开始取i个
                p = stoi(t);//这个子串为第一个进制数字      
                c = i;
            }
            else//如果是第二个逗号 
            {
    
    
                n = s.substr(c+1, i-c-1);//c是上一个逗号的位置,数字串第一个字符的位置为c+1,此时第二个逗号位置为i,数字串长度为i-c-1 
                t = s.substr(i+1);//从i+1到末尾为第二个进制数字
                q = stoi(t);
                break; 
            }
        }
    }
}
int getVal(char c)//字符转数值 
{
    
    
    if(c >= '0' && c <= '9')
        return c - '0';
    else
        return c - 'A' + 10;
}
char getCh(int n)//数值转字符 
{
    
    
    if(n >= 10)
        return n - 10 + 'A';
    else
        return n + '0';
}
void toNum(string s, int a[])//将数字串n转为数字数组a
{
    
    
    a[0] = s.length();
    for(int i = 1; i <= s.length(); ++i)
        a[i] = getVal(s[s.length()-i]);
}
void numCpy(int a[], int b[])//数字数组b拷贝给a 
{
    
    
    for(int i = 0; i <= b[0]; ++i)
        a[i] = b[i];
}
int Divide(int a[], int b, int k)//a /= b,k进制高精度数字a除以低精度数字b,返回值为余数 
{
    
    
    int r[N] = {
    
    }, m = 0;//r:商 m:中间临时使用的数字,是上一次小规模除法的余数,也是下一次的被除数 
    for(int i = a[0]; i >= 1; --i)
    {
    
    
        r[i] = (m * k + a[i]) / b;
        m = (m * k + a[i]) % b;
    }
    int r_i = a[0];
    while(r[r_i] == 0 && r_i > 1)
        r_i--;
    r[0] = r_i;
    numCpy(a, r);//把商赋值给a
    return m;
}
string toStr(int num[])//p进制高精度数字num转为q进制字符串 
{
    
    
    string r;
    int a[N], c;
    if(num[0] == 1 && num[1] == 0)//如果p进制高精度数字为0
        return "0";//直接返回字符串0 
    numCpy(a, num);
    while(!(a[0] == 1 && a[1] == 0))//只要高精度数字a不是0 
    {
    
    
        c = Divide(a, q, p);//p进制数字a /= q,余数为c 
        r = getCh(c) + r;
    }
    return r;
}
int main()
{
    
    
    int t, num[N];
    string s;
    cin >> t;
    while(t--)
    {
    
    
        cin >> s;
        parse(s);
        toNum(n, num);//将数字串n转为数字数组num 
        cout << toStr(num) << endl;
    }
    return 0;
}

解法2:高精度数字类

#include<bits/stdc++.h>
using namespace std;
#define N 305 //注意数字36进制数字50位Z转换为二进制后最多可以达到300位
struct HPN
{
    
    
    int a[N], k;//a:数字数组 k:进制 
    HPN(){
    
    }
    HPN(string s, int _k)
    {
    
    
        a[0] = s.length();
        for(int i = 1; i <= s.length(); ++i)
            a[i] = getVal(s[s.length()-i]);
        k = _k;
    }
    int getVal(char c)//字符转数值 
    {
    
    
        return isdigit(c) ? c - '0' : c - 'A' + 10;
    }
    char getCh(int n)//数值转字符 
    {
    
    
        return n >= 10 ? n - 10 + 'A' : n + '0'; 
    }
    int operator [] (int i)
    {
    
    
        return a[i];
    }
    void operator /= (int b)//a /= b 高精除低精 
    {
    
    
        int m = 0, d;//m:中间临时使用的数字,是上一次小规模除法的余数,也是下一次的被除数 
        for(int i = a[0]; i >= 1; --i)
        {
    
    
            d = m * k + a[i];//临时被除数 
            m = d % b;
            a[i] = d / b;
        }
        int l = a[0];
        while(a[l] == 0 && l > 1)
            l--;
        a[0] = l;
    }
    int operator % (int b)//a%b 高精模低精 
    {
    
    
        int m = 0;//m:中间临时使用的数字,是上一次小规模除法的余数,也是下一次的被除数 
        for(int i = a[0]; i >= 1; --i)
            m = (m * k + a[i]) % b;
        return m;
    }
    void changeSys(int x)//将当前数字的进制从k改为x 
    {
    
    
        HPN t = *this;//zero:高精度数字0,t先设为与自己相同
        k = x;
        if(a[0] == 1 && a[1] == 0)//如果自己本身是0
            return;//不用操作 
        int c, ai = 0;
        while(!(t[0] == 1 && t[1] == 0))//只要高精度数字t不是0 
        {
    
    
            a[++ai] = t % x;//高精模低精:t%x的结果填充到自己的数字数组a中 
            t /= x;//高精除低精 
        }
        a[0] = ai;
    }
    void show()
    {
    
    
        for(int i = a[0]; i >= 1; --i)
            cout << getCh(a[i]);
        cout << endl;
    }
};
void parse(string s, string &n, int &p, int &q)//解析输入的字符串s,得到p,q,n 
{
    
    
    int c1 = 0, c2 = 0;//c1, c2:第1、第2逗号的位置 
    for(int i = 0; i < s.length(); ++i)
    {
    
    
        if(s[i] == ',')
        {
    
    
            if(c1 == 0)
                c1 = i;
            else
                c2 = i;
        }
    }
    p = stoi(s.substr(0, c1));
    q = stoi(s.substr(c2+1));
    n = s.substr(c1+1, c2-c1-1);
}
int main()
{
    
    
    HPN num;
    int p, q, t;
    string s, n;
    cin >> t;
    while(t--)
    {
    
    
        cin >> s;
        parse(s, n, p, q);
        num = HPN(n, p);//p进制高精度数字num
        num.changeSys(q);
        num.show();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lq1990717/article/details/125381473