对于力扣2021数组的三角和的解题思路分析2.0(合数的逆元,欧拉定理和质因数分解第一部分

由解题思路1.0我们能得到最后的结果为

result = \sum_{i=0}^{i=n-1} (C_{n-1}^{i}\times nums_{i})

而根据题目要求,我们要对结果模10从而得到结果。

易知,大数运算的时间复杂度超过O(1),若这样写(粘贴的灵神的代码

class Solution:
    def triangularSum(self, nums: List[int]) -> int:
        n = len(nums)
        # 直接调用 math.comb 算出来的组合数很大,更快的写法见【Python3 预处理】
        return sum(comb(n - 1, i) * x for i, x in enumerate(nums)) % 10

作者:灵茶山艾府
链接:https://leetcode.cn/problems/find-triangular-sum-of-an-array/solutions/1390137/o-by-endlesscheng-952i/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

先不论大数运算给时间复杂度的增幅,就从直接调用Math.comb函数,时间复杂度为

O(n*(0+1+2+...+n-1)) = O(n^2)

所以我们考虑预处理组合数的模数,使复杂度降低。

这题巧妙之处在于模数是10而不是传统经常碰到的质数。

假如我们碰到了质数,那么我们可以根据费马小定理(MOD必须是质数

a^{MOD-2} \equiv 1(mod\ MOD)

用以下方式进行预处理。

MX = 100000
MOD  = 10**9 + 7
f = [0]*(MX + 1)
inv_f = [0]*(MX + 1)
for i in range(0,MX + 1):
    if i == 0 :
        f[i] = 1
    else:
        f[i] = ((f[i-1]%MOD)*i)%MOD
mx_inv = pow(f[MX],MOD - 2,MOD )
# print(mx_inv)
inv_f[-1] = mx_inv
for i in range(MX-1,-1,-1):
    inv_f[i] = (inv_f[i+1]*(i+1))%MOD
    # print((inv_f[i]*f[i])%MOD)
def comb(a,b):
    return (f[a]*inv_f[b]*inv_f[a-b])%MOD
print(comb(6,2))

而显然不是质数,对于合数,便进入了我们这题最精彩的部分,合数的模运算。

先讨论欧拉定理加质因数分解的方法。

什么是欧拉定理,也就是在a和b互质的前提下

a^{\varphi(b)}\equiv 1(mod \ b) \Rightarrow a^{\varphi(b)-1} \equiv \frac{1}{a}(mod \ b) 

顺带提一提欧拉函数,我记得一道蓝桥杯的题目用到过:

欧拉函数是指小于num的数中与num互质的数的数量

当b是质数的时候,

\varphi(b) = b - 1

(直观理解是质数与任何非他自身的数互质,注意1也与num互质)

当b是合数的时候,

\varphi(b) = n \times \prod_{i = 1}^{s}{\frac{p_{i}-1}{p_{i}}}

p_{i}是b的所有质因子。

故欧拉函数的计算公式有代码如下:

import math
def Phi(P):
    K = P  # 用来保存 P 的值,后面会用于计算
    for i in range(2, int(math.sqrt(P)) + 1):
        if P % i == 0:  # 如果 i 是 P 的因数
            K = K // i * (i - 1)  # 将 K 按照公式缩小
        while P % i == 0:  # 如果 i 是 P 的因数,除掉所有 i
            P //= i  # P 除以 i,直到 P 不能被 i 整除为止
    if P > 1:  # 如果 P 本身大于 1,说明 P 是一个大于 1 的质因数
        K = K // P * (P - 1)  # 继续按照公式处理
    return K

而本题为了满足欧拉定理a与b互质的条件,对b进行质因数拆分,即10被拆分为了2和5。

故有

ans = \sum(C_{n-1}^{i}\times nums_{i}) mod (10) \Rightarrow\\ ans = \sum(\frac{(n-1)!}{ (n-1-i)!\times i! }\times nums_{i} ) mod(2 \times 5) \Rightarrow \\

 \left\{ \begin{aligned} (n-1)! &= x_{1} \times 2^{a_{1}} \times 5^{b_{1}} \\ j! &= x_{2} \times 2^{a_{2}} \times 5^{b_{2}} \\ (n-1-j)! &= x_{3} \times 2^{a_{3}} \times 5^{b_{3}} \end{aligned} \right.

则有

ans = \sum{(\frac{x_{1}}{x_{2}\times x_{3}} \times 2^{a_{1} - a_{2} - a_{3}} \times 3^{b_{1} - b_{2} - b_{3}})\times nums_{j}}(mod\ 10)

今天就写这里了,刷道题就睡了。慢慢来吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值