卡普列加数是指正整数n满足其平方n²可在非首非尾处分割为左右两部分,且两部分数值之和等于n,右部分不能全为0;不能用pow()因浮点精度丢失,须用整数运算枚举divisor=10,100,…提取right=sq%divisor和left=sq/divisor,检查right≠0且left+right==n。

什么是卡普列加数,以及为什么不能直接用 pow() 拆位
一个正整数 n 是卡普列加数,当且仅当它的平方 n * n 在某个分割点(非末尾、非开头)被切成两部分后,两部分之和恰好等于 n,且**右边部分不能全为 0**(即不允许 100 → "1" + "00" 这种拆法)。比如 45:平方是 2025,拆成 "20" + "25" → 20 + 25 == 45,成立。
常见错误是试图用 pow(10, k) 取右半部分,但 pow() 返回 double,在大整数(如 n = 99999,n² ≈ 10¹⁰)时会因浮点精度丢失导致取模或除法出错。必须用整数运算模拟“切字符串”逻辑。
如何安全地枚举所有合法分割位置
对 n² 的十进制表示长度为 len,合法分割点只在第 1 到 len-1 位之间(即右半部分至少 1 位,左半部分也至少 1 位)。关键是要避免字符串转换——用纯数学方式提取左右两段:
- 设
sq = n * n,初始化divisor = 10 - 循环:每次用
sq % divisor得右半部分right,sq / divisor得左半部分left - 若
right != 0 && left + right == n,则返回true - 每次循环后
divisor *= 10,直到divisor > sq(即左半部分变成 0)
注意:divisor 从 10 开始,保证右半部分至少 1 位;right == 0 被显式排除,防止 100 → 1 + 00 这类无效拆分。
C++ 实现时的整数溢出与边界处理
n 最大能取多大?n² 必须在 long long 范围内(否则平方就溢出了)。所以输入 n 应限制在 sqrt(LLONG_MAX) ≈ 3e9 内。实际判断函数建议签名如下:
bool isKaprekar(long long n) {
if (n <p>几个易错点:</p>
divisor :必须包含等号,否则 <code>sq = 100时divisor = 100这次分割("1" + "00")会被跳过——但这是非法拆分,所以没问题;真正需要的是divisor = 10和100两次,而1000 > 100才停- 用
long long:哪怕n是int,n*n也可能溢出int,必须提升 -
n = 1是特例:1² = 1,唯一分割是"" + "1"或"1" + "",都不合法——但标准定义中1是卡普列加数,需单独处理(if (n == 1) return true;)
验证时别漏掉前导零隐含的分割
数学拆分不关心十进制表示里的前导零,例如 n = 297,n² = 88209,合法分割之一是 "88" + "209"(88 + 209 == 297),但 "8" + "8209" 不行(8 + 8209 ≠ 297)。你不需要手动补零或格式化字符串——sq % divisor 自动给出右段数值,它天然忽略前导零含义(88209 % 1000 == 209,不是 0209)。只要确保 right != 0,就排除了像 10000 这种右段全零的情况。
真正容易被忽略的是:有些数满足多个分割点(如 4879² = 23804641,可拆为 238 + 04641,但 04641 就是 4641,数值上成立),只要有一个成立就算卡普列加数。代码里遇到第一个就返回,不用全遍历。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











