高幂运算之后取模技巧

  • 场景:求(a^c)%k的值,这里c可能很大,直接求幂会造成溢出。
  • 先说结论:在高幂运算之后取模,我们可以先将底数取一次模,然后求幂的过程中,两两相乘后再次取模
  • 对于两数相乘然后取模有以下公式:
    ( a ∗ b ) % k = ( a % k ) ( b % k ) % k (a * b) \% k = (a \% k)(b \% k) \% k (ab)%k=(a%k)(b%k)%k

  • 证明:

    假设
    a = A k + B ; b = C k + D a = Ak +B;b = Ck + D a=Ak+Bb=Ck+D

    其中 A,B,C,D 是任意常数,那么:
    a ∗ b = A C k 2 + A D k + B C k + B D ( a ∗ b ) % k = ( A C k 2 + A D k + B C k + B D ) % k = 0 + 0 + 0 + B D % k = B D % k a*b = ACk^2 + ADk + BCk +BD \\ (a * b) \% k = (ACk^2 + ADk + BCk +BD)\%k \\=0+0+0+BD \% k \\=BD \% k ab=ACk2+ADk+BCk+BD(ab)%k=(ACk2+ADk+BCk+BD)%k=0+0+0+BD%k=BD%k

    又因为:
    a % k = B ; b % k = D a \% k = B;b \% k = D a%k=Bb%k=D

    所以:
    ( a ∗ b ) % k = B D % k = ( a % k ) ( b % k ) % k (a * b) \% k = BD \% k = (a \% k)(b \% k) \% k (ab)%k=BD%k=(a%k)(b%k)%k

高幂运算的情况

  • 由于高幂运算很容易造成数字溢出,因此不能直接求幂
  • 而高幂运算后取模,例如a^c%k,相当于c个a连乘然后对k取模:(a*a*a....*a) % k

    • 这里b个a相乘很容易溢出,应该考虑如何缩小相乘的结果
  • 根据上面公式可知:
    ( a ∗ a ∗ a . . . ∗ a ) % k = ( ( a % k ) ( a % k ) ( a % k ) . . . ( a % k ) ) % k (a*a*a...*a) \% k=((a\%k)(a\%k)(a\%k)...(a\%k)) \% k (aaa...a)%k=((a%k)(a%k)(a%k)...(a%k))%k

    • b=(a%k),则相当于
      ( a ∗ a ∗ a . . . ∗ a ) % k = ( b ∗ b ∗ b ∗ . . . b ) % k (a*a*a...*a) \% k=(b*b*b*...b)\%k (aaa...a)%k=(bbb...b)%k

      • 其中b是小于k的,这样就保证了每个因子都小于k,然后我们需要进一步缩小相乘结果
  • c个b相乘对k取模,可以把前面两个因子相乘结果看做一个数,后面c-2个因子相乘的结果看做一个数:
    ( b ∗ b ∗ b ∗ . . . b ) % k = ( ( b ∗ b ) % k ∗ ( b ∗ b ∗ b . . ∗ b ) % k ) % k = ( ( b ∗ b ) % k ∗ ( b % k ) ( b % k ) ( b % k ) . . . ( b % k ) ) % k = ( ( b ∗ b ) % k ∗ b ∗ b ∗ . . . ∗ b ) % k (b*b*b*...b)\%k = ((b*b)\%k * (b*b*b..*b)\%k)\%k \\= ((b*b)\%k * (b\%k)(b\%k)(b\%k)...(b\%k))\%k \\=((b*b)\%k *b*b*...*b)\%k (bbb...b)%k=((bb)%k(bbb..b)%k)%k=((bb)%k(b%k)(b%k)(b%k)...(b%k))%k=((bb)%kbb...b)%k

    • 假设B=b*b,那么有
      ( ( b ∗ b ) % k ∗ b ∗ b ∗ . . . ∗ b ) % k = ( B ∗ b ∗ b . . . . ∗ b ) % k = ( ( B ∗ b ) % k ∗ ( b ∗ b . . . ∗ b ) ) % k ((b*b)\%k *b*b*...*b)\%k=(B*b*b....*b)\%k \\=((B*b)\%k * (b*b...*b) )\%k ((bb)%kbb...b)%k=(Bbb....b)%k=((Bb)%k(bb...b))%k
  • 依此类推,因此可以得出结论在高幂运算之后取模,我们可以先将底数取一次模,然后求幂的过程中,两两相乘后再次取模

    // 计算a的c次方对k取模的结果
    public int pow(int a ,int c ,int k){
        // 保证每个因子都小于base
        a %= k;
        int res = 1;
        for (int i = 0; i < c; i++) {
            // 两两相乘
            res *= a;
            // 对乘法结果求模
            res %= k;
        }
        return res;
    }
    
  • 很多个不同数相乘后取模也可以这样做,只需要第一步for循环将每个数字先取一次模即可,防止两两相乘的时候溢出
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一酒。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值