幂取模这个原理书上一笔带过没看懂,后来得益于大神讲解https://zhidao.baidu.com/question/1447700874365286820.html
终于懂了:积的取余等于每个数取余的乘积再取余
接下来就是代码和详细的注解:
'''
让每一个选手选择两个数Ai和Bi,计算所有pow(Ai,Bi)之和,然后对一个除数取模,得到余数
输入:任务数:正整数Z,每个任务中,除数为整数M,[1,45000],选手人数H,[1,45000]
接下来是H行的2个元素组合,表示每个选手选择的数字
'''
'''
证明:积的余数等于余数的积再取余数
若a÷b=c余d,e÷b=f余g.
则a加e的和除以b等于b分之a加b分之e
所以,左式的余数等于d加g
所以,和的余等于余的和
a乘e的积除以b等于b分之(bc+d)乘(bf+g)的积,打开括号,分子变为b^2cf+bcg+bdf+dg.
所以,左式的余数等于分bai子的余数,即和的余数,因为和的余数等于余数的和,又因为b^2cf,bcg,bdf三者除以b都余零
所以,最后左式的余数变为dg的余数
所以,得出结论,积的余数等于余数的积再取余数。
'''
import math
import time
# 输入:
Z = 3
Ms = [16, 36123, 17]
Hs = [4,1,1]
Hs_num = [[[2,3], [3,4], [4,5], [5,6]], [[2374859, 3029382]], [[3,18132]]]
# 预期输出:2,13195,13
# 原方法:性能不佳
# pre1 = time.time()
# for i in range(Z):
# M = Ms[i]
# H = Hs[i]
# H_num = Hs_num[i]
# sum = 0
# for j in range(H):
# sum = sum + pow(H_num[j][0], H_num[j][1])
# sum = sum % M
# print(sum)
# print(time.time() - pre1)
# 采用幂取模算法(分治)
def pow_mod(x, n, m):
if n == 0:
return 1
if x == 0:
return 0
y = pow_mod(x, math.floor(n / 2), m)
if (n % 2) == 1:
return (y * y * x) % m
else:
return (y * y) % m
# pre2 = time.time()
for i in range(Z):
M = Ms[i]
H = Hs[i]
H_num = Hs_num[i]
sum = 0
for j in range(H):
sum = sum + pow_mod(H_num[j][0], H_num[j][1], M)
sum = sum % M
print(sum)
# print(time.time() - pre2)
运行结果: