模拟 N 进制回文数生成:数码数组逐位做 a + reverse(a) 并处理进位,至多 30 步判回文;必须按数码面值直接模拟,不能转整数(数据里有数码 ≥ N 的输入)。
OJ: roj
题目 ID: 1309
难度:入门
标签:入门高精度模拟python
创建: 2026-09-30 04:18
更新: 2026-10-05 09:01
题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,称之为回文数。给定进制 0–9、A–F 表示),定义一步操作为:把 Impossible。若
输入:一行,进制 Impossible。样例:输入 9 87,输出 6。
思路
把 2 37,转整数语义就错了),然后反复做「Impossible。
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-07-05 22:10
# update_at: 2026-07-05 22:10
import sys
DIGITS = '0123456789ABCDEF' # 值 → N 进制字符,N 最大 16,恰好够用
VALUES = {c: i for i, c in enumerate(DIGITS)} # 大写字母的值
VALUES |= {c.lower(): i for i, c in enumerate(DIGITS) if c.isalpha()} # 补小写
def add_reverse(a: list[int], base: int) -> list[int]:
"""返回 a + reverse(a) 在 base 进制下的数码数组(低位在前,可能多一位)。"""
s = [x + y for x, y in zip(a, a[::-1])]
for i in range(len(s)):
carry, s[i] = divmod(s[i], base)
if carry: # 进位累加到更高位
if i + 1 < len(s):
s[i + 1] += carry
else:
s.append(carry)
return s
def solve() -> None:
base_s, m = sys.stdin.read().split()
base = int(base_s) # 进制 N(2 < N <= 10 或 N = 16)
a = [VALUES[c] for c in m][::-1] # 数码数组,低位在前
for step in range(31): # 第 0 步先判初始是否回文
is_palindrome = a == a[::-1]
if is_palindrome:
print(step)
return
if step == 30: # 30 步用尽仍未回文
break
a = add_reverse(a, base) # 一次 N 进制加法
print('Impossible')
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 09:01
* update_at: 2026-10-05 09:07
*/
#include <cstdio>
#include <cstring>
typedef long long ll;
const int MAXL = 1005;
int base; // 进制 N(2 < N <= 10 或 N = 16)
int len; // 当前数码长度
int a[MAXL]; // 数码数组,低位在前
// 字符转面值:0-9、A-F(含小写)
int char_value(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
return -1;
}
// 判断当前数码序列(低位在前)是否回文
bool is_palindrome() {
for (int i = 0, j = len - 1; i < j; i++, j--)
if (a[i] != a[j]) return false;
return true;
}
// 一次 N 进制加法:a = a + reverse(a)
// 与评测机(原 main.py,已 AC)语义一致:只对原有 len 位做 "除 base 取余" 归化,
// 最高位溢出的进位直接追加落地,不再继续归约(数据可能有越界数码)
void add_reverse() {
int s[MAXL + 5]; // 逐位求和的结果,s[i] = a[i] + a[len-1-i]
int n = len;
int bound = n; // 只归化原有 len 位,与 Python 的 range(len(s)) 一致
for (int i = 0; i < len; i++) s[i] = a[i] + a[len - 1 - i];
for (int i = 0; i < bound; i++) { // 上界固定为旧 len,新追加的最高位不再归约
int carry = s[i] / base;
s[i] %= base;
if (carry > 0) {
if (i + 1 < n) s[i + 1] += carry;
else { s[n] = carry; n++; } // 最高位进位直接落地
}
}
len = n;
for (int i = 0; i < len; i++) a[i] = s[i];
}
int main() {
char str[MAXL];
scanf("%d %s", &base, str);
len = strlen(str);
for (int i = 0; i < len; i++) a[i] = char_value(str[len - 1 - i]); // 低位在前
// 第 0 步先判初始是否回文,之后最多做 30 次加法
for (int step = 0; step <= 30; step++) {
if (is_palindrome()) {
printf("%d\n", step);
return 0;
}
if (step == 30) break;
add_reverse();
}
printf("Impossible\n");
return 0;
}