洛谷 P1015 [NOIP1999 普及组] 回文数
[NOIP1999 普及组] 回文数
题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个十进制数 \(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 \le N \le 10\) 或 \(N=16\))进制数 \(M\)(\(100\) 位之内),求最少经过几步可以得到回文数。如果在 \(30\) 步以内(包含 \(30\) 步)不可能得到回文数,则输出 Impossible!。
输入格式
两行,分别是 \(N\),\(M\)。
输出格式
如果能在 \(30\) 步以内得到回文数,输出格式形如 STEP=ans,其中 \(\text{ans}\) 为最少得到回文数的步数。
否则输出 Impossible!。
样例 #1
样例输入 #1
10
87
样例输出 #1
STEP=4
分析
这里考察高精度加法
原理根我们平时手写的竖式
分享一下我的高精度加法的模板(我习惯用vector储存大整数)
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> C;
int t = 0;//存进位
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);//①
t /= 10;//②
}
if (t) C.push_back(t);//处理最后进位
return C;//结果
}
以上是针对 \(10\) 进制大整数加法的模板,
在这题中要求是 \(N\) 进制,
那么可以将模板中的①和②处的10改为 \(N\) 即可。
即
C.push_back(t%N);t/=N;
在这题中还需要判断是否为回文数,
可以使用双指针 \(i\) 从头, \(j\) 从末尾各自向中间移动,
只要出现 a[i]!=a[j] 则说明不是回文数。
那么就可以按题目要求进行 \(30\) 次操作,若没找到回文数则输出 \(Impossible!\)。
接下来是代码:
AC CODE (cpp)
#include<bits/stdc++.h> //noip 1999 回文数
using namespace std;
bool check(vector<int> a){
for(int i = 0,j = a.size()-1;i<j;i++,j--)if(a[i]!=a[j])return false;
return true;
}
vector<int> f(vector<int> a){
for(int i = 0,j = a.size()-1;i<j;i++,j--)swap(a[i],a[j]);
return a;
}
int main(){
int N;
cin>>N;
string s;
cin>>s;
vector<int> A;
for(int i = s.size()-1;~i;--i){
if(isdigit(s[i]))A.push_back(s[i]-'0');
else A.push_back(s[i]-'A'+10);
}
if(check(A))return puts("0"),0;
for(int T = 1;T<=30;T++){
vector<int> B = f(A);
int t = 0;
vector<int> C;
for(int i = 0;i<A.size();i++){
t += A[i]+B[i];
C.push_back(t%N);
t/=N;
}
if(t)C.push_back(t);
if(check(C))return printf("STEP=%d",T),0;
A.clear();
A = C;
}
return puts("Impossible!"),0;
}
如有错误请指出。

浙公网安备 33010602011771号