Kaprekar数
* * * *
拉格朗日计划
* * * *
Kaprekar数

若自然数n的平方可以按数位分拆成两部分,且这两部分之和等于n,则称数n为Kaprekar数。

例如$55^2=3025$,把3025拆分成30和25两部分,则$30+25=55$,因此55是Kaprekar数。

拆分后不能改变数字的顺序,并且要求两部分都不为0,但两者的长度可以不同。

输出1到25000000之间的所有Kaprekar数,每个数单独打印一行。

本题难度:



解答

由于数据范围非常大,逐个检验显然是不可取的。

以下实现使用的是该页面的算法。

设$10^n-1=ab$且$\gcd(a,b)=1$,设a'是a在模b乘法群中的逆,即$aa'=1\bmod b$,那么$aa'$就是一个Kaprekar数,并且除了$1$和形如$10^k-1$的数以外的所有Kaprekar数均在此法生成的数中。

n依次取2到8,枚举$10^n-1$的约数,并用辗转相除法计算a',最后筛出不超过25000000的数即可。

本题第一名的代码非常短,不清楚是怎么实现的。

最终代码有七行。

代码长度:308字节 vs. 全站第一:70字节。

import itertools as r
def g(a,b):
  if b<1:return 1,0,a
  x,y,d=g(b,a%b)
  return y,x-(a//b)*y,d
t=[10**i-1for i in range(1,9)]
*map(print,filter(lambda x:x<25000000,sorted(set([1]+t+[*r.chain(*[[a*(g(a,b)[0]%b),b*(g(b,a)[0]%a)]for n in t for a in range(2,int(n**0.5)+1)if a*(b:=n//a)==n and g(a,b)[2]<2])])))),