Toj1788-Raising Modulo Numbers(幂取模(分治法)+ python)

幂取模这个原理书上一笔带过没看懂,后来得益于大神讲解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)

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我有明珠一颗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值