注:本题在不同的OJ输出格式不同,请多多注意!!!!!!!!!!!!!!!!!!!!!!
题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个十进制数 56,将 56 加 65(即把 56 从右向左读),得到 121 是一个回文数。
又如:对于十进制数 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(100 位之内),求最少经过几步可以得到回文数。如果在 30 步以内(包含 30 步)不可能得到回文数,则输出 Impossible!
。
输入
两行,分别是 N,M。
输出
如果能在 30 步以内得到回文数,输出格式形如 STEP=ans
,其中 ans 为最少得到回文数的步数。
样例输入输出
输入: 输出:
10 STEP=4
87
思路:
高精,通过进制转换来判断是否回文。
STEP 1:声明进制、高精数组及输入字符串。
STEP 2:定义用于将字符串形式的数字转换为高精数组形式的函数tonum,处理方式如下:
-
如果是数字字符('0'-'9'),转换为对应的数值。
-
如果是字母字符('A'-'Z'),转换为对应的数值(10-35)。
STEP 3:定义函数用于生成数字的反序表示,就是一个逆序存放,我觉得不用多讲的
STEP 4:高精加法,懂的都懂
STEP 5:判断高精数是否回文,方法是遍历数组的前半部分,比较对应位置的数字是否相等,如果全部相等,返回true
;否则返回false
。
STEP 6:输入,tonum()将读入字符串转为高精数组,进行迭代,isPalin()检查是否回文,是就输出当前次数并结束,否则生成a
的反序数组b,
将a
和b
相加,结果存回a
。…… 30次后,输出impossible
代码(标注释的是在洛谷提交的)
#include<bits/stdc++.h> using namespace std; #define N 105 int n,a[N],b[N]; char s[N]; void tonum(char*s,int*a) { int len=strlen(s); for(int i=1;i<=len;i++) { if(s[len-i]>='0'&&s[len-i]<='9') { a[i]=s[len-i]-'0'; } else { a[i]=s[len-i]-'A'+10; } } a[0]=len; } void genOpp(int*a,int*b) { for(int i=1;i<=a[0];i++) { b[i]=a[a[0]+1-i]; } b[0]=a[0]; } void addToA(int*a,int*b) { int c=0; for(int i=1;i<=a[0]||i<=b[0];i++) { a[i]+=b[i]+c; c=a[i]/n; a[i]%=n; } if(c>0) { a[++a[0]]=c; } } bool isPalin(int*a) { for(int i=1;i<=a[0]/2;i++) { if(a[i]!=a[a[0]-i+1]) { return false; } } return true; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>s; tonum(s,a); for(int i=0;i<=30;i++) { if(isPalin(a)) { cout/*<<"STEP="*/<<i; return 0; } genOpp(a,b); addToA(a,b); } cout<<"Impossible"; // cout<<"Impossible!"; return 0; }
运行结果