题目
https://www.patest.cn/contests/pat-a-practise/1024
已知非回文串可以通过不断和自身逆序相加来得到回文串,称为一次操作,如67+76=143+341=484的操作次数为2。给定一个正数N和操作的最大次数,判断该数串在最大操作次数内能否得到回文串。
解题思路
由于N最大可以为10^10,操作次数最多可以为100次,所以数字长度会很长,在long long int内会溢出,所以必须要用大整数相加。
用二维数组num存放每一次操作得到的数字(num[0]为输入的原始数字)一维数组row_cnt记录num每一行的数字有效长度。第step次运算前先判断是否已经得到回文串,若已经得到则跳出循环,否则取num[step-1]这一行的数字进行逆序相加和判断进位,存放到num[step]这一行,更新row_cnt[step]。
第一次交的时候测试点6和8都没有通过,仔细检查了代码是没有问题的,后来看了大神博客才知道是二维数组的列宽太小了,20和50都不够,100才能全部通过。(有可能每次都要溢出进位,所以今后要想清楚了再声明啊!)
自己的方法太复杂了,https://www.liuchuo.net/archives/2329这篇博客里用STL的string和reverse来快速解题。真是高下立见。
STL的方法如下:
判断回文串只需reverse当前字符串s得到t,用s==t来判断是否回文。
计算时也只需要将t逐位加到s上,判断进位,(正着加和反着加是没有区别的,为自己智商捉急),最后将s逆序即得到这一次操作后的结果。
AC代码
复杂的二维数组法
#include <iostream>
#include <cstring>
using namespace std;
int num[110][100]; //存放每一步的运算结果
int row_cnt[110] = {0}; //num矩阵每行的有效数字长度
void print(int row) //输出第row行数字
{
for (int j = row_cnt[row] - 1; j >= 0; --j)
cout << num[row][j];
cout << endl;
}
bool isPalindromic(int row) //判断第row行是不是回文数字
{
bool flag = true;
int maxj = row_cnt[row];
for (int j = 0; j <= maxj/2; ++j) //判断回文串
{
if (num[row][j] != num[row][maxj-1-j])
{
flag = false;
break;
}
}
return flag;
}
int main()
{
memset(num, 0, sizeof(num));
int limit;
char str[20];
cin >> str >> limit;
int j = 0;
for (int i = strlen(str)-1; i >= 0; --i)
num[0][j++] = str[i] - '0';
row_cnt[0] = j;
int step = 0;
while(step < limit)
{
bool check = isPalindromic(step);
if (check)
{
print(step);
cout << step << endl;
return 0;
}
step += 1;
int last = row_cnt[step-1]; //last为上一行的数字长度
for (int j = 0; j < last; ++j) //逆序相加
{
num[step][j] += num[step-1][j] + num[step-1][last-1-j];
num[step][j+1] = num[step][j] / 10;
num[step][j] %= 10;
}
row_cnt[step] = (num[step][last] == 0)?last:last+1;
}
print(step);
cout << limit << endl;
return 0;
}
简练的STL大法:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string s;
void add()
{
string t = s;
reverse(t.begin(), t.end());
int len = s.length(), carry = 0;
for (int i = 0; i<len; ++i) //将t各位累加到s上
{
s[i] = s[i] + t[i] + carry - '0'; //注意s是字符串
if (s[i] > '9') //要用字符'9'判断进位
{
s[i] = s[i] - 10;
carry = 1;
}
else carry = 0;
}
if (carry == 1) s += '1'; //溢出进位
reverse(s.begin(), s.end());
}
int main()
{
int limit;
cin >> s >> limit;
int step = 0;
while (step < limit)
{
string t = s;
reverse(t.begin(), t.end());
if (s == t) //判断回文
{
cout << s << endl << step;
return 0;
}
step += 1;
add();
}
cout << s << endl << step;
return 0;
}