混沌者 pat basic 练习七十四 宇宙无敌加法器

心得:

这题有几点需要注意:

1.刚开始担心进位的时候会超过当前进制数,如某位是二进制,会不会进位一个2?然后再相加的时候出现了4,那么向下一位进几?很纠结

 

后来看了别人的文章就发现这些担心是多余的

有这几个原则:

(1.)给出的数字不会超过这一位的进制数-1,例如有一位是5进制,这一位的数最高也就是4

(2.)和普通十进制加法一样,进位的数字要么1要么0,也就是说进给下一位的最大也就1;即使某一位加上了上一位进的1,得到的最大结果也只会向下一位进1

第一:这个很明显,单个数字不可能超过它的进制数-1,不然没意义

第二:先考虑第一位数,这个位相加没有加上上一位的进位(因为这是第一位,当然没有上一位),假设它是n进制,最大的数也就是n-1,两个n-1相加为2n-2,当相加结果为2n的时候才会向下一位进2,而结果却是2n-2,离2n还差2,所以第一位最大进1

假设第k位数向k+1位进1,k+1位的进制为n,两个最大的数n-1相加是2n-2,再加上进的位1结果是2n-1,也没到2n,它的进位也是1;所以进位最大是1,和最大也就是“十几”

 

2.应该对int和long long的范围敏感

int              4个字节 2^31-1   10位数 21开头

long long   8个字节 2^63-1 19位数 92开头

 

明显20位数相加,整型肯定不行了,必须用字符串,测试点3,4也如此

 

3.算加法时,n位数相加(最长的那个保证n位数),要考虑n+1位,因为还有第n位的进位

 

4.要想去除字符串前面一串的“0”:

(1.)可以使用stringstream转成整型,会自动去除,但缺点是长度不能超过整型的范围

(2.)无用的不好去除时,可以把有用的存到另一个地方,即遍历这个字符串,当发现第一个不是0的字符时,把剩下的字符串赋给另一个变量

(3.)也不一定要删除,可以只显示有用的,这样效果一样

bool find_no_zero=false;
for(int i=0;i<res.size();i++)
    {
        if(res.at(i)!='0'||find_no_zero)
        {
            find_no_zero=true;
            cout<<res.at(i);
        }
    }

find_no_zero作用是防止中间的0没被显示输出,

这个写法思想就像   想进入有锁的房子,进去的方式是找到钥匙或者门是开着的,而有了钥匙就能使门打开

前面的0被"锁着"而不能输出,发现第一个不是零的字符就像找到了钥匙并打开了门,而后面的不管是什么都能被输出了,因为门已经开了,所以这个思想要熟记

 

 

题目:

地球人习惯使用十进制数,并且默认一个数字的每一位都是十进制的。而在 PAT 星人开挂的世界里,每个数字的每一位都是不同进制的,这种神奇的数字称为“PAT数”。每个 PAT 星人都必须熟记各位数字的进制表,例如“……0527”就表示最低位是 7 进制数、第 2 位是 2 进制数、第 3 位是 5 进制数、第 4 位是 10 进制数,等等。每一位的进制 d 或者是 0(表示十进制)、或者是 [2,9] 区间内的整数。理论上这个进制表应该包含无穷多位数字,但从实际应用出发,PAT 星人通常只需要记住前 20 位就够用了,以后各位默认为 10 进制。

在这样的数字系统中,即使是简单的加法运算也变得不简单。例如对应进制表“0527”,该如何计算“6203 + 415”呢?我们得首先计算最低位:3 + 5 = 8;因为最低位是 7 进制的,所以我们得到 1 和 1 个进位。第 2 位是:0 + 1 + 1(进位)= 2;因为此位是 2 进制的,所以我们得到 0 和 1 个进位。第 3 位是:2 + 4 + 1(进位)= 7;因为此位是 5 进制的,所以我们得到 2 和 1 个进位。第 4 位是:6 + 1(进位)= 7;因为此位是 10 进制的,所以我们就得到 7。最后我们得到:6203 + 415 = 7201。

输入格式:

输入首先在第一行给出一个 N 位的进制表(0 < N ≤ 20),以回车结束。 随后两行,每行给出一个不超过 N 位的非负的 PAT 数。

输出格式:

在一行中输出两个 PAT 数之和。

输入样例:

30527
06203
415

 

输出样例:

7201

 

 

思路:

先将两个数的前面填上足够的零,使它们的长度是进制表的长度

然后把某一位的两个数字和上一位的进位按照十进制相加,然后再转成对应的进制,转换后的结果十位作为下一位的进位,个位作为本位的结果,这是基本做法,但是还有一些细节

 

1.假如是n位数相加,那么结果要考虑n+1位,因为第n位的数相加时,可能会向下进一位,

比如测试用例

48527
37416
1

结果是100000,这也是测试点1的注意点

 

2.题目说最大数长度可能是20位的数,而(有符号)long long最长位19位,所以结果一定要用字符串输出,不然会出错

这也是测试点3 4的注意点,这两个测试点应该用的长数

 

3.输出结果要去掉字符串前面多余的0,并且如果结果字符串全是0的话,要输出一个0

比如测试用例

0
0
0

结果是0,这也是测试点5的注意点

 

 

代码:

#include<iostream>
#include<sstream>
using namespace std;
int change(int sum,int sys)
{//这个函数是将某数转成对应的进制,并返回一个整型结果
    if(sum==0)
        return 0;
    string temp;
    stringstream ss;
    int val;
    if(sys==0)//不要忘了0代表10进制,直接除0会错误
        sys=10;
    while(sum!=0)
    {
        temp.insert(0,1,(sum%sys)+'0');
        sum/=sys;
    }
    ss<<temp;
    ss>>val;
    return val;
}
int main()
{
    string table,num1,num2,res;
    int index=0;
    bool find_no_zero=false;
    cin>>table>>num1>>num2;
    int up[21]={};//存进位数的数组
    num1.insert(0,table.size()-num1.size(),'0');//将数字在前面补零,补到和进制表一样长度
    num2.insert(0,table.size()-num2.size(),'0');
    for(int i=table.size()-1;i>=0;i--,index++)
    {
        int temp,i1=num1[i]-'0',i2=num2[i]-'0',sum=0;//i1,i2为对应字符转成的数字
        sum=i1+i2+up[index];//两数和上一位的进位数相加
        temp=change(sum,table[i]-'0');//然后转成对应进制
        res.insert(0,1,temp%10+'0');//转换后的数个位作为本位结果
        up[index+1]=temp/10;//十位作为向下一位的进位
    }
    res.insert(0,1,up[index]+'0');//不要忘了把最后一位的进位也算上
    for(int i=0;i<res.size();i++)
    {//不输出前面的0
        if(res.at(i)!='0'||find_no_zero)
        {
            find_no_zero=true;
            cout<<res.at(i);
        }
    }
    if(!find_no_zero)//如果全是0,就输出0
        cout<<0;
    return 0;
}

 

另一种去掉前面的零的方法,这个做法是将不是0的字符存到另一个字符串里

 

bool all_zero=true;
for(int i=0;i<res_t.size();i++)
    {
        if(res_t.at(i)!='0')
        {
            all_zero=false;
            for(int j=i;j<res_t.size();j++)
                res+=res_t.at(j);
            break;
        }
    }
    if(all_zero)
        cout<<"0"<<endl;
    else
        cout<<res<<endl;

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值