目录
一、前言
您好,我是夏日弥,叫我“夏”或者“小弥”都可以。
本次带来每周例行PTA测试讲解。
将涉及 高精度加法 和 10进制转换成2-16进制 问题。
让我们来看看今天的5道题。
二、例题部分
2.1、进制转换
将十进制整数n(−231≤n≤231−1)转换成k(2≤k≤16)进制数。注意,10~15分别用字母A、B、C、D、E、F表示。
输入格式:
首先输入一个正整数T,表示测试数据的组数,然后是T组测试数据。每组测试数据输入两个整数n和k。
输出格式:
对于每组测试,先输出n,然后输出一个空格,最后输出对应的k进制数。
输入样例:
4
5 3
123 16
0 5
-12 2
输出样例:
5 12
123 7B
0 0
-12 -1100
2.1.1、题解1
因为涉及11~16进制转换,要用到A、B、C、D、E、F字母,所以我们要用字符串来解决这个问题:
首先,我们编一个万能的进制转换函数,类型为string型。
我们用 t=n%进制数 来获取最后一位数t,如十进制123取3;
再用 n/=进制数 来销毁最后一位数,如十进制的123销毁3,变成12;
小tips:t为int型,要转化为char型,可以这么做
t+‘0’ 比如说 t=1 ,1+‘0’ = ‘1’;
ans+= ‘1’;;
如果t>10,就 t-10 + ‘A’ ;如 10 - 10 + ‘A’ = ‘A’;
ans+= ‘A’;
string intToA(int n,int radix)
{
string ans=""; //定义空的字符串ans;
do{
int t=n%radix; //取该进制的最后一位,比如十进制的123中的3;
if(t>=0&&t<=9) ans+=t+'0';//如果该进制的最后一位数是0~9,则直接加入ans;t为int型,t+'0'被转化为char型;
else ans+=t-10+'A';//如果该进制的最后一位数是比9大,则转化为相应的进制表示,如10转为A,11转为B等等;
n/=radix;//销毁最后一位,如123销毁3变成12;
}while(n!=0);//用do-while确保输入为0时返回ans="0";
reverse(ans.begin(),ans.end());//string类的子函数,反转字符串的元素,如321反转成123;
return ans; //返回ans;
}
然后呢,特化判断输入的值小于0的情况:
只需要在其绝对值结果前加一个‘-’号就可以了;
#include<bits/stdc++.h>
using namespace std;
string intToA(int n,int radix)
{
string ans=""; //定义空的字符串ans;
do{
int t=n%radix; //取该进制的最后一位,比如十进制的123中的3;
if(t>=0&&t<=9) ans+=t+'0';//如果该进制的最后一位数是0~9,则直接加入ans;t为int型,t+'0'被转化为char型;
else ans+=t-10+'A';//如果该进制的最后一位数是比9大,则转化为相应的进制表示,如10转为A,11转为B等等;
n/=radix;//销毁最后一位,如123销毁3变成12;
}while(n!=0);//用do-while确保输入为0时返回ans="0";
reverse(ans.begin(),ans.end());//string类的子函数,反转字符串的元素,如321反转成123;
return ans; //返回ans;
}
int main(){
int n=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
int num,k;
scanf("%d %d",&num,&k);
if(num>=0)cout<<num<<" "<<intToA(num,k)<<endl;
else cout<<num<<" -"<<intToA(num*-1,k)<<endl;
}
}
2.1.2、题解2
准备逃课!
来看这个函数!
它被包含在这个头文件#include<stdlib.h>
itoa(num,s,k);//num为整形int或long,s为字符数组,k为想要转化的进制数;
返回类型为string;
#include<bits/stdc++.h>
using namespace std;
int main(){
int num,k;
char s[100];
cin>>num>>k;
cout<<itoa(num,s,k);//num为整形int或long,s为字符数组,k为想要转化的进制数
}
但是它输出为11进制等的数时,输出的11为‘a’而不是'A';
所以我们写一个小循环替换大小写;
最终答案为:
#include<bits/stdc++.h>
using namespace std;
string intToA(int n,int radix)
{
string ans="";
do{
int t=n%radix;
if(t>=0&&t<=9) ans+=t+'0';
else ans+=t-10+'a';
n/=radix;
}while(n!=0);
reverse(ans.begin(),ans.end());
return ans;
}
int main(){
int n=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
int num,k;
char s[999];
scanf("%d %d",&num,&k);
switch(k){
case 2:{
itoa(num,s,2);
printf("%s",s);
break;
}
case 3:{
itoa(num,s,3);
printf("%s",s);
break;
}
case 4:{
itoa(num,s,4);
printf("%s",s);
break;
}
case 5:{
itoa(num,s,5);
printf("%s",s);
break;
}
case 6:{
itoa(num,s,6);
printf("%s",s);
break;
}
case 7:{
itoa(num,s,7);
printf("%s",s);
break;
}
case 8:{
itoa(num,s,8);
printf("%s",s);
break;
}
case 9:{
itoa(num,s,9);
printf("%s",s);
break;
}
case 10:{
itoa(num,s,10);
printf("%s",s);
break;
}
case 11:{
itoa(num,s,11);
for(int i=0;s[i];i++){
if(s[i]>='a'&&s[i]<='z')s[i]+=('A'-'a');
}
printf("%s",s);
break;
}
case 12:{
itoa(num,s,12);
for(int i=0;s[i];i++){
if(s[i]>='a'&&s[i]<='z')s[i]+=('A'-'a');
}
printf("%s",s);
break;
}
case 13:{
itoa(num,s,13);
for(int i=0;s[i];i++){
if(s[i]>='a'&&s[i]<='z')s[i]+=('A'-'a');
}
printf("%s",s);
break;
}
case 14:{
itoa(num,s,14);
for(int i=0;s[i];i++){
if(s[i]>='a'&&s[i]<='z')s[i]+=('A'-'a');
}
printf("%s",s);
break;
}
case 15:{
itoa(num,s,15);
for(int i=0;s[i];i++){
if(s[i]>='a'&&s[i]<='z')s[i]+=('A'-'a');
}
printf("%s",s);
break;
}
case 16:{
itoa(num,s,16);
for(int i=0;s[i];i++){
if(s[i]>='a'&&s[i]<='z')s[i]+=('A'-'a');
}
printf("%s",s);
break;
}
}
}
}
2.2、 函数返回一个整数的反序数 (20 分)
编写函数返回形式参数(一个正整数)的反序数。主函数功能为:输入一个整数N,输出N的反序数。
输入样例:
21000
结尾无空行
输出样例:
12
结尾无空行
输入样例:
1234
结尾无空行
输出样例:
4321
结尾无空行
2.2.2 题解
#include<bits/stdc++.h>
using namespace std;
int rev(int x){
int a[1000],i=0,sum=0;
while(x!=0)
{
a[i]=x%10;
i++;
x/=10;
}
for(int j=0;j<i;j++){
sum+=a[j];
sum*=10;
}
sum/=10;
return sum;
}
int main(){
int n;
cin>>n;
cout<<rev(n);
}
参照2.1的解法,注意因为我们是数组是倒序记录的,所以用这个方法写就可以了
for(int j=0;j<i;j++){
sum+=a[j];
sum*=10;
}
sum/=10;
return sum;
来看看vector吗
#include<bits/stdc++.h>
using namespace std;
int main(){
long long int sum=0,n;
vector<int> a;
cin>>n;
while(n!=0){
a.push_back(n%10);
n/=10;
}
for(auto x:a){
sum+=x;
sum*=10;
}
cout<<sum/10;
}
之后会为感兴趣的同学讲vector;
2.3、 大整数A+B (10 分)
输入两个整数A、B,求 A + B。
输入格式:
首先输入一个正整数T,表示测试数据的组数,然后是T组测试数据。每组测试输入2个正整数A、B。整数可能很大,但每个整数的位数不会超过1000。
输出格式:
对于每组测试输出两行数据;第一行输出"Case #:",#表示测试组号,第二行输出形式为“A + B = Sum”,Sum表示A+B的结果。每两组测试数据之间空一行。
输入样例:
2
1 2
88888888888888888888888 11111111111111111111111
输出样例:
Case 1:
1 + 2 = 3
Case 2:
88888888888888888888888 + 11111111111111111111111 = 99999999999999999999999
出处:
HDOJ 1002
2.3.1 题解
#include<bits/stdc++.h>
using namespace std;
string P (string & num,string add){
int g=0;
if(num.length()<add.length()){
string t=num;
num=add;
add=t;
}//如果num的长度小于add的长度,则交换num和add的内容;
string t (num.length()-add.length(),'0');
add= t+add;//在数字头部补全add的长度,使其与num一样长;如123补全为000123;
int len1=num.length(),len2=add.length();
for(int i=len1-1;i>=0;i--){
int t=((num[i]-'0') +(add[i]-'0') + g);//模拟竖式,g为进制;
num[i]=t%10+'0';//从低位开始计算;
g=t/10;//记录进制是否为空;
}
if(g!=0){
num.insert(0,string(1,(char)g+'0'));
}//判断头部进制;
return num;
}
int main(){
int n,n1=1,p=0;
cin>>n;
for(int i=0;i<n;i++){
string a,b,c;
cin>>a>>b;
c=a;
if(p!=0)cout<<endl<<endl;
p=1;
printf("Case %d:\n",n1);
n1++;
cout<<c<<" + "<<b<<" = "<<P(a,b);
}
}
可以用相同的思路来编写高精度减法,高精度乘法,高精度除法;
救命!
2.4 求组合数 (16 分)
本题要求编写程序,根据公式Cnm=m!(n−m)!n!算出从n个不同元素中取出m个元素(m≤n)的组合数。
建议定义和调用函数fact(n)
计算n!
,其中n
的类型是int
,函数类型是double
。
输入格式:
输入在一行中给出两个正整数m和n(m≤n),以空格分隔。
输出格式:
按照格式“result = 组合数计算结果”输出。题目保证结果在double
类型范围内。
输入样例:
2 7
结尾无空行
输出样例:
result = 21
结尾无空行
2.4.1 题解
#include<bits/stdc++.h>
using namespace std;
double fact(int n){
if(n>=1)return fact(n-1)*n;
else return 1;
}
int main(){
int n,m;
double sum=0;
cin>>m>>n;
sum=(fact(n))/((fact(m))*fact(n-m));
printf("result = %.lf",sum);
}
水题,大家自己玩!
三、尾声
感谢您的阅读;
下次小夏会为您讲解一些基础的STL知识,期待您的阅读。
特别鸣谢hasmokan提供的封面图;
夏日弥死傲娇
2021.11.22