卡普列加数指正整数n,其平方n²从右截取d位(d为n的位数)得right,余下高位为left,满足left+right=n且left不为空;不能直接用pow()因double精度在d>15时丢失,导致取模错误,应改用整数循环计算10^d。

什么是卡普列加数,以及为什么不能直接用 pow() 拆位
卡普列加数(Kaprekar number)的定义是:对一个正整数 n,其平方 n * n 可以被**从某一位中间切开**(非前导零位置),分成左右两部分 left 和 right(允许 right 为 0,但 left 不能为空),满足:left + right == n,且 right 的位数必须等于 n 的位数(即切分点必须在最后 d 位和前面部分之间,d = to_string(n).length())。
常见误解是“任意切”,实际规则严格:比如 45 是卡普列加数,因为 45*45 == 2025,而 20 + 25 == 45,且 25 是最后 2 位(45 有 2 位);但 100 不是,因为 100*100 == 10000,按规则只能切成 100 + 00(即 100 + 0)或 10 + 000(000 是 3 位?不,n=100 有 3 位,所以 right 必须是最后 3 位 → 000,left=10,10+0==10≠100)。
关键陷阱:pow(10, d) 在 double 下可能精度丢失(尤其 d > 15),导致取模或除法出错。应改用整数幂计算或字符串长度推导。
如何安全地提取最后 d 位和前面部分
给定 n,先算 sq = (long long)n * n(防溢出),再确定位数 d = to_string(n).size()。然后需枚举所有合法切分点:只有一种——right 必须是最后 d 位,left 是高位剩余部分(可为 0,但不能整个 sq 都进 right,即 left 至少得有 1 位或为 0)。
实操建议:
- 用
long long base = 1;循环d次算出base = 10^d(避免pow) right = sq % base;-
left = sq / base;(整除,自动截断) - 注意:若
sq (例如 <code>n=1→sq=1,d=1,base=10),则left == 0,right == 1,此时0 + 1 == 1→1是卡普列加数(符合定义) - 不要忽略
n == 1和n == 9(81 → 8 + 1 = 9)这类边界
C++ 判断函数怎么写才不出错
以下是一个健壮的判断函数,处理了溢出、位数、前导零(由取模天然规避)和单数字情况:
bool isKaprekar(int n) {
if (n long long base = 1;
for (int i = 0; i <p>}</p>
说明:
- 输入限定为正整数,负数/0 直接返回
false - 用
long long存sq,避免int溢出(如n=99999→sq≈10^10) - 不依赖
string拆分数字,只用它获取位数,避免手动处理前导零逻辑 - 没有额外分支判断 “right 是否有前导零”——因为
% base的结果天然就是最后d位数值(0025 % 100 == 25),而定义中只要求right占d位,值本身无影响
哪些数容易误判?测试时重点盯这几个
这几个数是经典坑点,写完务必验证:
-
isKaprekar(1)→ true(1*1=1,d=1,base=10,left=0,right=1) -
isKaprekar(9)→ true(81,d=1,base=10,left=8,right=1) -
isKaprekar(45)→ true(2025,d=2,base=100,left=20,right=25) -
isKaprekar(10)→ false(100,d=2,base=100,left=1,right=0,1+0=1≠10) -
isKaprekar(99)→ true(9801,d=2,base=100,left=98,right=1→ 等等,98+1=99,但right=01是 2 位?9801 % 100 == 1,不是01;不过定义只关心数值,不要求字符串补零,所以正确)
真正容易漏的是位数变化带来的 base 计算错误,比如把 n=100 当作 2 位而非 3 位——所以一定要用 to_string(n).size(),别用 log10 或手动除法数位。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











