蓝桥杯A组——Python(10.04)Day6
重新规划了题目表达W-week,T-题号
W2T1-寻找整数CRT:
有一个不超过10的17次方的正整数n,知道这个数除以2至49后的余数如下表所示,求这个正整数最小是多少?
刚开始没去自学 CRT 和 extended_gcd 写了个史山代码,但胜在简单无脑。
#提前进行了质数提取和余数为零的剔除
a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
m = [1, 2, 4, 4, 0, 10, 0, 18, 15, 16, 27, 22, 1, 11, 5]
# 计算所有质数的乘积
product = 1
for p in a:
product *= p
a1 = [] # 除a[i]外其他质数乘积
for i in range(len(a)):
a1.append(product // a[i])
a2 = [] # 乘法逆元列表
for i in range(len(a)):
# 使用pow函数计算模逆元
a2.append(pow(a1[i], -1, a[i]))
n = 0
for i in range(len(a)):
n += a1[i] * a2[i] * m[i]
n = n % product
print(n)
%product 一开始写成了%pow(10,17) 怎么run都答案错误,我都快哭了,自学 extended_gcd 重新写了才发现问题,我是真的会谢
——————————————————————————————————
接下来是分函数写的
def extended_gcd(a, b):
"""扩展欧几里得算法,返回gcd(a, b)以及系数x, y使得ax + by = gcd(a, b)"""
if a == 0:
return b, 0, 1
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1-(b//a)*x1
y = x1
return gcd, x, y
欧几里得算法给我一种熟悉又陌生的感觉,求gcd可以直接用函数,一搜才发现这就是辗转相除法,简直小丑了。
扩展欧几里得算法是求系数x, y使得ax + by = gcd(a, b),用在求逆元和之后的CRT算法里
def mod_inverse(a, m):
"""计算a在模m下的逆元,如果不存在则返回None"""
gcd, x, y = extended_gcd(a, m)
if gcd != 1:
return None # 逆元不存在,a和m不是互质的
else:
return x % m
def CRT(a, m):
"""中国剩余定理求解"""
N = 1
for n in a:
N*=n
result = 0
for ai, mi in zip(a, m):
Ni = N // ai
inv_Ni = mod_inverse(Ni, ai)
result += mi * Ni * inv_Ni
return result%N
a = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
m = [1, 2, 4, 4, 0, 10, 0, 18, 15, 16, 27, 22, 1, 11, 5]
# 去除m中对应a为质数但余数为0的元素
filtered_a = [x for i, x in enumerate(a) if m[i] != 0]
filtered_m = [x for x in m if x != 0]
print(CRT(filtered_a, filtered_m))
enumerate真的好用,好评
写代码还是以数学为基础的,本来还是两道题,但学 广义欧几里得 和 CRT 花的时间太久了,所以今天只有一题,学 extended_gcd 和 CRT 也算是完成学习任务了。
出去玩回来了,国庆结束,重回学习状态,加油!
————————————————————————————————————————
W2(D6)——end