PAT1 1024 Palindromic Number

博客围绕判断数N在K次变换内能否变成回文数展开。给出题目大意、输入输出要求及样例,变换指将N逆序后与N相加。解析指出本题原本考大整数加法,使用python则可直接相加判断。

题目链接
我的github

题目大意

一个数如果从前往后和从后往前看是一样的,那么这个数就是回文数。
现在给数 N N N( ≤ 1 0 10 \leq 10^{10} 1010)和 K K K( ≤ 100 \leq 100 100),分别表示初始的数和最大的变换步数,求 N N N K K K次变换内能否变成回文数。变换是指将 N N N逆序后得到数 M M M,然后 N + = M N+=M N+=M

输入

每组包含一个测试用例,每个用例为一行有两个正整数 N N N K K K

输出

对每个例子输出两行,第一行输出 N N N K K K次变换内所得的最小回文数,如果不能得到回文数,就输出 N N N变换 K K K次得到的数,第二行输出 N N N K K K次变换内最少需要多少次变成回文数,如果不能变成回文数,就输出 K K K

样例输入

67 3

69 3

样例输出

484
2

1353
3

解析

这题原本要考大整数的加法,但是python就没那么麻烦,直接相加然后判断即可

def check(s):   #判断回文
    if s == s[::-1]:
        return True
    else:
        return False


def solve():
    n, k = map(int, input().split())
    cnt = 0
    for i in range(k):
        if check(str(n)):
            break
        n = n + int(str(n)[::-1])
        cnt += 1
    print(n)
    print(cnt)


if __name__ == "__main__":
    solve()
这是一个 **子集问题的变种**:我们需要统计所有非空子集(也可以是空集?看样例),使得子集元素之是一个**回文数(palindromic number)**。 --- ## ✅ 题意解析 - 给定 `N` 个正整数(可能重复) - 你可以选择任意数量的数(1 到 N 个,即非空子集) - 求有多少种**选择方式(子集)**,其为**回文数** - 子集不同 ⇨ 即使相同也算不同(只要选的元素位置不同就算不同) 但注意:输入样例中: ``` 输入: 3 1 1 100 输出:3 ``` 我们来分析这个样例。 --- ## 🔍 样例分析:`[1, 1, 100]` 所有非空子集有 $2^3 - 1 = 7$ 个: | 子集 | 元素 | | 是否回文 | |------|------|----|---------| | {1} | [1] | 1 | ✅ 是 | | {1} | [1] | 1 | ✅ 是 | | {100} | [100] | 100 | ❌ 否("100" ≠ "001") | | {1,1} | [1,1] | 2 | ✅ 是 | | {1,100} | [1,100] | 101 | ✅ 是 | | {1,100} | [1,100] | 101 | ✅ 是 | | {1,1,100} | [1,1,100] | 102 | ❌ 否 | 现在检查每个是否是回文数: - 1 → 是 - 1 → 是 - 100 → 不是 - 2 → 是 - 101 → 是 - 101 → 是 - 102 → 不是 所以满足条件的子集有: 1. 第一个 1=1 2. 第二个 1=1 3. {1,1} → =2 4. {1,100}(第一个1+100)→ =101 5. {1,100}(第二个1+100)→ =101 共 **5 个** 但输出是 **3**! 这说明我们的理解有问题。 --- ## ❗ 重新思考:是不是相同的值视为同一种选择? 或者题目中的“ways”是指不同的**值**? 但题目说:“how many ways you can choose the numbers”,应该是不同的子集算不同的方式。 然而输出是 `3`,不是 `5`。 ### 可能原因:题目认为两个 `1` 是不可区分的? 即数组 `[1,1,100]` 中有两个相同的 `1`,如果它们来自不同位置但值相同,在组合中视为相同? 但这与常规“子集计数”不符。 除非题目意思是:**不同的子集,即使元素相同、位置不同,但如果值一样,就合并?** 不,通常不会这样。 再试另一种可能性:我们列出所有**不同的值**中,哪些是回文? - =1 → 回文 ✅ - =2 → 回文 ✅ - =101 → 回文 ✅ - 其他:100,102 → 不是 → 有 3 个**不同的回文值** 但题目问的是“多少种选择方式”,不是“多少个回文” → 所以不是这个解释。 --- ## 🚫 矛盾!我们得到 5,样例输出是 3 ### 新思路:也许题目不允许选单个数字?但样例用了单个 1 等等,再看一遍题目: > "you can choose 1,2,3,....or n of them" → 至少选一个 → 正确 > 输出是 3 只有当我们把两个 `1` 视为同一个,并且只算一次=1 的情况时才可能。 但即便如此,还有: - =1(出现两次,但只算一次?) - =2({1,1}) - =101(出现两次,但只算一次?) → 如果按**不同的子集**算,是 5 → 如果按**不同的值**算,是 3(1,2,101) → 所以很可能:**题目在问有多少个不同的回文值?** 但题目原文是: > how many ways you can choose the numbers so that the sum of them is palindromic number. 这里的 “ways” 应该是子集的数量,而不是不同的数量。 --- ## ✅ 正确解读:可能是 **LeetCode 类型的“子集去重”问题** 即:虽然有两个 `1`,但因为值相同,某些子集被视为相同? 例如,在集合 `{1,1,100}` 中,选择第一个 `1` 或第二个 `1` 被视为同一种方式? 但在标准算法题中,如果是**索引不同**,就是不同的子集。 除非题目明确说是“distinct subsets by value”。 但我们来看另一个角度:最大可能是多少? - N ≤ 20,ai ≤ 100 → 最大 = 20×100 = 2000 - 回文数范围小:从 1 到 2000 的回文数大约只有几百个 我们可以用 **折半搜索(Meet-in-the-Middle) + 回文判断** 来暴力枚举所有子集,然后统计为回文数的子集数量。 然后运行样例看看。 --- ## ✅ 重新计算样例(假设两个 1 是可区分的) 子集如下(设 a=1, b=1, c=100): 1. a → sum=1 ✅ 2. b → sum=1 ✅ 3. c → sum=100 ❌ 4. ab → sum=2 ✅ 5. ac → sum=101 ✅ 6. bc → sum=101 ✅ 7. abc → sum=102 ❌ → 总共 5 个满足条件 但输出是 3 ### 唯一可能:题目意思是——输出的是**有多少个不同的回文值**? 即: - =1 → 回文 - =2 → 回文 - =101 → 回文 共 3 个不同的回文值 → 输出 3 ✅ 这就对上了! --- ## ✅ 最终理解 题目问的是: > 有多少个**不同的值 S**,使得存在某个非空子集,其为 S,且 S 是回文数? 即:不是统计子集个数,而是统计**能构成的回文值的种类数** 例如: - =1 可以构成 → 计 1 次 - =2 可以构成 → 计 1 次 - =101 可以构成 → 计 1 次 - =100 不行 → 不计 总数 = 3 --- ## ✅ 解法步骤 1. 使用位掩码或 DFS 枚举所有非空子集的 2. 将所有可能的存入一个集合(set)中 3. 遍历这个集合,判断每个是否是回文数 4. 统计回文的数量 由于 N ≤ 20,最多 $2^{20} \approx 1e6$ 种子集,完全可行 --- ## ✅ C++ 实现 ```cpp #include <iostream> #include <vector> #include <set> #include <string> #include <algorithm> using namespace std; // 判断一个数是否是回文数 bool isPalindrome(int n) { string s = to_string(n); string t = s; reverse(t.begin(), t.end()); return s == t; } int main() { int N; while (cin >> N) { vector<int> nums(N); for (int i = 0; i < N; ++i) { cin >> nums[i]; } set<int> possibleSums; // 枚举所有非空子集 for (int mask = 1; mask < (1 << N); ++mask) { int sum = 0; for (int i = 0; i < N; ++i) { if (mask & (1 << i)) { sum += nums[i]; } } possibleSums.insert(sum); } // 统计其中有多少个是回文数 int count = 0; for (int s : possibleSums) { if (isPalindrome(s)) { count++; } } cout << count << endl; } return 0; } ``` --- ## ✅ 再验证样例 输入:`[1, 1, 100]` 所有非空子集: - 1 (from first 1) - 1 (second 1) → 已存在 - 100 - 1+1=2 - 1+100=101 - 1+100=101 → 已存在 - 1+1+100=102 → 集合:{1, 2, 100, 101, 102} 回文判断: - 1 → 是 - 2 → 是 - 100 → 否 - 101 → 是 - 102 → 否 → 共 3 个回文值 → 输出 `3` ✅ --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值