【题解·洛谷】P1015 [NOIP1999 普及组] 回文数

#温馨提示:此文章使用的是MD编辑器,在小程序上查看可能会出现乱码,敬请谅解

题目介绍

题目描述

本题难度:普及-
算法标签:模拟 高精度

若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。

例如:给定一个十进制数 56 56 56,将 56 56 56 65 65 65(即把 56 56 56 从右向左读),得到 121 121 121 是一个回文数。

又如:对于十进制数 87 87 87

STEP1: 87 + 78 = 165 87+78=165 87+78=165
STEP2: 165 + 561 = 726 165+561=726 165+561=726
STEP3: 726 + 627 = 1353 726+627=1353 726+627=1353
STEP4: 1353 + 3531 = 4884 1353+3531=4884 1353+3531=4884

在这里的一步是指进行了一次 N N N 进制的加法,上例最少用了 4 4 4 步得到回文数 4884 4884 4884

写一个程序,给定一个 N N N 2 ≤ N ≤ 10 2 \le N \le 10 2N10 N = 16 N=16 N=16)进制数 M M M 100 100 100 位之内),求最少经过几步可以得到回文数。如果在 30 30 30 步以内(包含 30 30 30 步)不可能得到回文数,则输出 Impossible!

输入格式

两行,分别是 N N N M M M

输出格式

如果能在 30 30 30 步以内得到回文数,输出格式形如 STEP=ans,其中 ans \text{ans} ans 为最少得到回文数的步数。

否则输出 Impossible!

样例 #1

样例输入 #1

10 \texttt{10} 10
87 \texttt{87} 87

样例输出 #1

STEP=4 \texttt{STEP=4} STEP=4

题解代码及思路

本题是一道考察高精度知识的题目。
由于数据范围过大,我们需要使用高精度来完成。
本代码使用如下方法:

  • 定义常量 S S S 为缓冲区大小,以及变量 n n n 存储进制数、 a [   ] a[\,] a[] 作为辅助数组、 l l l 存储当前处理的数字长度、 c [   ] c[\,] c[] 存储原始输入的数字字符数组、 d [   ] d[\,] d[] 用于临时存储反向读取的数字。

  • add() 函数负责将当前数与它的反向读取数相加,并更新到 c[] 数组中,同时处理进位情况和去除高位前导零。

  • pd() 函数判断当前数是否为回文数。

  • main() 函数:
    输入进制数 n n n 和待处理的数(字符形式) c c c
    将字符转换为对应的数值存入 c [ ] c[] c[]
    初始化步数计数器 s t e p step step 0 0 0
    使用循环不断进行加法操作直至得到回文数或超过 30 30 30 步。
    如果在 30 30 30 步以内得到了回文数,则输出 STEP= 后跟最少步数;否则输出 Impossible!

其他解析见代码注释。

AC代码如下

#include <bits/stdc++.h> 
using namespace std;

const int S = 303; // 定义常量S,用于存储数字的缓冲区大小

int n, a[S], l; // n: 存储进制数,a[]: 辅助数组,l: 存储当前处理的数字长度
char c[S], d[S]; // c[]: 存储原始输入的字符数组,d[]: 临时存储反向读取的数字

void add() {// add() 函数:将原数字与其反向读取后的数字相加并更新至 c[]
    for (int i = 0; i < l; i++) { // 将 d[] 中的内容逆序添加到 c[] 的末尾
        d[l - i - 1] = c[i];
    }
    l += 2; // 增加总长度表示额外添加了反向读取的数字
    for (int i = 0; i < l; i++) { // 进行高精度加法和处理进位
        c[i] += d[i];
        if (c[i] >= n) { // 若某位大于等于n,则向上一位进位
            c[i + 1]++;
            c[i] -= n;
        }
    }
    while (!c[l - 1]) // 移除高位前导零
        l--;
}
bool pd() { // pd() 函数:判断当前数字是否为回文数
    for (int i = 0; i < l; i++) { // 检查从左到右与从右到左读取的每一位是否相同
        if (c[i] != c[l - 1 - i]) {
            return false;
        }
    }
    return true; // 若是回文数,返回true
}

int main() {
    cin >> n >> c; // 输入进制数 n 和待转换的字符串 c
    l = strlen(c); // 计算字符串 c 的长度
    for (int i = 0; i < l; i++) { // 将字符串中的字符转换为对应的数值
        if (c[i] >= '0' && c[i] <= '9') 
            c[i] -= '0';
        else 
            c[i] = c[i] - 'A' + 10; // 处理十六进制中字母 A-F 对应的数值
        
    }
    int step = 0; // 定义步数计数器
    while (!pd()) { // 不断执行加法直到得到回文数或超过30步
        step++;
        if (step > 30) 
            break;
        add();
    }
    if (step <= 30) // 根据步数输出结果
        cout << "STEP=" << step;
    else
         cout << "Impossible!";
    
    return 0;
}
  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值