题解:洛谷 P1206 回文平方数

【题目来源】

洛谷:P1206 [USACO1.2] 回文平方数 Palindromic Squares - 洛谷

【题目描述】

回文数是指从左向右念和从右向左念都一样的数。如 12321 就是一个典型的回文数。

给定一个用十进制表示的正整数 B,输出所有 [1,300] 中,它的平方用 B 进制表示时是回文数的数。

【输入】

共一行,一个单独的正整数 B

【输出】

每行两个 B 进制的符合要求的数字,第二个数是第一个数的平方,且第二个数是回文数。

注意大于 9 的数,用字母表示。如用 A 表示 10,B 表示 11,用第 n 个大写字母表示 n+9。

【输入样例】

10

【输出样例】

1 1
2 4
3 9
11 121
22 484
26 676
101 10201
111 12321
121 14641
202 40804
212 44944
264 69696

【核心思想】

  1. 问题分析:给定进制 \(B\),要求找出所有 \([1,300]\) 范围内的整数 \(i\),使得 \(i^2\)\(B\) 进制表示下是回文数,并输出 \(i\)\(i^2\)\(B\) 进制形式。这是一个进制转换 + 回文判断 + 枚举模拟问题。

  2. 算法选择

    • 枚举:由于数据范围很小(\(1 \le i \le 300\)),直接枚举每个整数并验证
    • 进制转换:将十进制数转换为 \(B\) 进制字符串,用短除法取余,并用字母表示大于 9 的数字
    • 回文判断:将转换后的字符串与其反转比较,判断是否为回文
    • 模拟:对每个 \(i\),模拟计算平方、转换进制、判断回文、输出的完整流程
  3. 关键步骤

    • 读取输入:进制 \(B\)
    • 枚举整数\(i\)\(1\)\(300\)
    • 计算平方\(t = i \times i\)
    • 进制转换
      • \(i\) 转换为 \(B\) 进制字符串 \(s1\)
      • \(t\) 转换为 \(B\) 进制字符串 \(s2\)
      • 转换方法:不断对 \(B\) 取余,将余数映射为字符(\(0-9\) 用数字,\(10+\) 用大写字母)
    • 回文判断:检查 \(s2\) 是否等于其反转字符串
    • 输出结果:若 \(s2\) 是回文,输出 \(s1\)\(s2\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(300 \cdot \log_B 90000)\),由于数据范围固定,实际接近常数;若推广到 \(N\),则为 \(O(N \log_B N)\)
    • 空间复杂度:\(O(\log_B N)\),存储转换后的字符串
  5. 进制转换 + 回文判断的核心思想

    • 短除法转进制:通过不断除以 \(B\) 取余,得到低位到高位的数字,再逆序拼接成字符串
    • 字符映射规则:大于 9 的数字用大写字母表示(\(10 \to A\)\(11 \to B\),以此类推)
    • 回文对称性:回文串正读反读相同,只需比较首尾对称位置是否一致
    • 小范围直接枚举:利用题目中 \(300\) 的范围限制,暴力枚举即可通过
    • 适用于进制转换、数字回文、字符串对称性判断等问题

【解题思路】

【算法标签】

普及- #模拟

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int k, t;
string s1, s2;
string dtok(int t, int k)  // 十进制转k进制模板
{
    string ans = "";  // 定义空字符串
    while (t>0) {  // 使用数位拆分思路,当t不为0时
        int x = t % k;  // 除以k,得到k进制的余数
        if (x<10) ans = char(x+'0') + ans;  // 拼接到ans字符串的前面(注意不是追加到后面)
        else ans = char(x-10+'A') + ans;  // 对于大于10的,转为大写字母
        t = t / k;  // 更新t为整数部分
    }
    if (ans.empty()) ans = "0";  // 特判t为0时,直接返回0
    return ans;  // 返回拼接后的字符串
}

bool isPal(string s) {  // 回文字符串的判断
    for (int i=0; i<s.size(); i++) {  // 从头开始遍历
        if (s[i]!=s[s.size()-1-i]) { // 逐位比较,如果遇到不相等的,就返回false
            return false;
        }
    }
    return true;  // 遍历完还没false的就返回true
}
int main()
{
    cin >> k;  // 输入k(不用b是因为方便记忆十进制转k进制模板)
    for (int i=1; i<=300; i++) {  // 从1遍历至300
        t = i*i;  // 得到平方数
        s1 = dtok(i, k);  // 将i转为B进制
        s2 = dtok(t, k);  // 将平方数转为B进制
        if (isPal(s2)) {  // 判断平方数(字符串)是否为回文数(字符串)
            cout << s1 << " " << s2 << endl;  // 如果是,则打印B进制的i和平方数
        }
    }
    return 0;
}

【运行结果】

10
1 1
2 4
3 9
11 121
22 484
26 676
101 10201
111 12321
121 14641
202 40804
212 44944
264 69696
posted @ 2026-07-30 10:15  团爸讲算法  阅读(2)  评论(0)    收藏  举报