问题 A: 回文数
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个10进制数56,将56加65(即把56从右向左读),得到121是一个回文数。
又如:对于10进制数87:
STEP1:87+78 = 165 STEP2:165+561 = 726
STEP3:726+627 = 1353 STEP4:1353+3531 = 4884
在这里的一步是指进行了一次N进制的加法,上例最少用了4步得到回文数4884。
写一个程序,给定一个N(2< =N< =10或N=16)进制数M(其中16进制数字为0-9与A-F),求最少经过几步可以得到回文数。
如果在30步以内(包含30步)不可能得到回文数,则输出“Impossible!”
输入格式
两行,N与M
N(2< =N< =10或N=16)
M最多不超过100位
输出格式
如果能在30步以内得到回文数,输出“STEP=xx”(不含引号),其中xx是步数;否则输出一行”Impossible!”(不含引号)
输入样例 复制
9
87
输出样例 复制
STEP=6
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int m[100]={0}; //全局变量m用于读入数据、比较
int cnt=0; //全局变量cnt用于计算次数
int palin(int m[],int len){ //判断是否是回文数组的函数
int i,j=len-1;
int flag=1;
for(i=0;i<len/2;i++){
if(m[i]!=m[j]){
flag=0;
break;
}
j--;
}
return flag;
}
void invert(int m[],int n,int d){ //进行n进制回文相加操作的函数
int i,j;
int vert[d]; //转置数组
cnt++;
for(i=0,j=d;i<d;i++){
vert[i]=m[j-1];
j--;
}
for(i=0;i<d;i++){
m[i]+=vert[i];
if(m[i]>=n){ //模拟进位
m[i+1]++;
m[i]-=n;
}
}
int len;
for(i=99;i>=0;i--){
if(m[i]!=0){
len=i+1; //len是m有效位数的长度,等会传入函数
break;
}
}
if(palin(m,len)!=1&&cnt<=30){ //不是回文数组且cnt<=30时,继续执行invert函数
invert(m,n,len);
}
}
int main(){
int n,step=0,i,len,j;
cin>>n;
char str[101]={0};
scanf("%s",str);//读入str,将str拆解给m
for(i=0,j=strlen(str)-1;i<strlen(str);i++){
if(n<=10)m[i]=str[j]-'0';
else{ //16进制
if(str[j]>='0'&&str[j]<='9'){
m[i]=str[j]-'0';
}else if(str[j]>='A'&&str[j]<='F'){
m[i]=str[j]-'A'+10;
}
}
j--;
}
for(i=99;i>=0;i--){
if(m[i]!=0){
len=i+1; //计算m有效位数的长度
break;
}
}
invert(m,n,len);
if(cnt>=31)cout<<"Impossible!";
else cout<<"STEP="<<cnt;
return 0;
}
问题 B: 高精度加法题目描述
输入两个大整数a和b,输出这两个整数的和。a和b都不超过100位。
输入格式
输入包括两行,第一行为一个非负整数a,第二行为一个非负整数b。两个整数都不超过100位,两数的最高位都不是0。
输出格式
输出一行,表示a + b的值。
输入样例 复制
20100122201001221234567890
2010012220100122
输出样例 复制
20100122203011233454668012
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
int a[100]={0},b[100]={0};
char str1[101]={0},str2[101]={0};
int i,j;
scanf("%s",str1);
scanf("%s",str2);
for(i=0,j=strlen(str1)-1;i<strlen(str1);i++){
a[i]=str1[j]-'0';
j--;
}
for(i=0,j=strlen(str2)-1;i<strlen(str2);i++){
b[i]=str2[j]-'0';
j--;
}
for(i=0;i<max(strlen(str1),strlen(str2));i++){
a[i]=a[i]+b[i];
if(a[i]>=10){
a[i+1]++;
a[i]%=10;
}
}
for(i=99;i>=0;i--){
if(a[i]!=0)break;
}
for(;i>=0;i--){
cout<<a[i];
}
return 0;
}
问题 C: 高精度减法
题目描述
输入两个大整数a和b,输出这a-b的结果。a和b都不超过100位。
输入格式
输入包括两行,第一行为一个非负整数a,第二行为一个非负整数b。两个整数都不超过100位,两数的最高位都不是0。
输出格式
输出一行,表示a - b的值。
输入样例 复制
111111111111111111111111
111111111111111111111111
输出样例 复制
0
数据范围与提示
结果可能为负数
#include<iostream>
#include<cstring> //使用c风格字符串
#include<algorithm>
using namespace std;
int main(){
int a[100]={0},b[100]={0};
char str1[101]={0},str2[101]={0};
int i,j,flag=0,k=0,cnt=0;
scanf("%s",str1); //%s可以过滤回车
scanf("%s",str2);
for(i=0,j=strlen(str1)-1;i<strlen(str1);i++){
a[i]=str1[j]-'0'; //将str每位倒序存入数组
j--;
}
for(i=0,j=strlen(str2)-1;i<strlen(str2);i++){
b[i]=str2[j]-'0';
j--;
}
for(i=0;i<max(strlen(str1),strlen(str2));i++){
a[i]=a[i]-b[i]; //作减法
if(a[i]<0){ //模拟借位
a[i]=10+a[i];
a[i+1]--;
}
}
for(i=99;i>=0;i--){
if(a[i]!=0){ //找到非零的第一位
break;
}
}
if(a[i]<0){ //如果是负数
a[i]++;
flag=-1;
k--;
for(i=i-1;i>0;i--){
a[i]=9-a[i]; //负数的话,需要进行此运算
}
a[0]=10-a[0];
for(i=0;i<strlen(str1);i++){ //但要小心还有a[0]=10的情况,如200-500
if(a[i]==10){ //如果a[0]=10,进位,再考虑a[1]是否也需要进位,因为只有100位,没有设置break
a[i]=0;
a[i+1]++;
}
}
}
for(i=99;i>=0;i--){
if(a[i]!=0){
k=i; //找到现在非零的首位
break;
}
}
if(flag==-1)cout<<"-"; //如果是负数输出负号
for(k;k>=0;k--){
cout<<a[k];
}
return 0;
}
问题 E: 视频合并问题
题目描述
有多个视频需要合并为一个视频,假设一次只能将两个视频进行合并,合并需要的时间为该两个视频的时间之和。请计算将多个视频合并为一个视频需要的最小时间为多少?
输入格式
输入的第一行包含一个正整数n,表示共有n个视频需要合并。其中n不超过100。 第二行中有n个用空格隔开的正整数,分别表示n个视频的时间。
输出格式
输出包括一个正整数,即合并需要的最小时间。
输入样例 复制
8
5 29 7 8 14 23 3 11
输出样例 复制
271
代码
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n;
cin>>n;
int k=n;
int a[n];
int i,j=n-1;
for(i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
long long sum=0;
if(n>1){
for(i=0;i<k-1;i++){
a[0]+=a[1]; //合并时间最短的两个视频
sum+=a[0];
for(j=1;j<n-1;j++){
a[j]=a[j+1]; //数组从2开始逐个前移一位
}
n--;
sort(a,a+n); //再次排序
}}
cout<<sum;
return 0;
}