最近做到一题数学题
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from secret import flag
assert flag[:6] == "flag{b"
assert flag[-1] == "}"
t = int(flag[5:-1], 16)
assert t > 10**99
assert t < 10**100
assert pow(t, 2, 10**100) == t
一个数字,他的平方取模后得到自己。
这个是标准的守形数,或者称为自守数、自构数。
网上找了一圈守形数的计算方法,都是用枚举,计算量小的时候还可以,这题数字大到100位,根本没办法枚举计算。
守形数定义
一个n位数x,满足
x^2 % (10^n) = x,即为守形数
尝试数学分析:
守形数定理
守形数的低位一定是守形数
证明如下
假设一个守形数xy,他的低位是y,即假设x为第n位数
守形数为 x*10^n + y
满足 (x*10^n + y) ^ 2 % (10^n) = x * 10^n + y
即 (x * 10^2n + 2* x * y * 10 ^ n + y ^2) % (10^n) = y ^2
y ^2 = x * 10 ^ n + y
y满足守形数的定义,所以得证,守形数的低位必是守形数。
计算大数守形
我们知道,一位数的守形数有1、5、6,二位数的有 25、76,我们以2位数进行扩展
得到100位的守形数为:
6046992680891830197061490109937833490419136188999442576576769103890995893380022607743740081787109376
和
3953007319108169802938509890062166509580863811000557423423230896109004106619977392256259918212890625
其中
6046992680891830197061490109937833490419136188999442576576769103890995893380022607743740081787109376
满足16进制首位为b,得到结果。
kk = ['5','6']
j=1
while(1):
lenkk = j
for c in kk:
if len(c) == lenkk:
for i in range(10):
b = str(i) + c
slend = pow(10,len(b))
if pow(int(b),2,slend) == int(b):
kk.append(b)
if len(b) == 100:
print(b)
j=j+1
if j == 100:
break
得到结果
3953007319108169802938509890062166509580863811000557423423230896109004106619977392256259918212890625
6046992680891830197061490109937833490419136188999442576576769103890995893380022607743740081787109376
n位数的守形数计算复杂度由O(10^n)降低到O(n)