第11届蓝桥杯 Java C 组真题 A:指数计算

【问题描述】

7月1日是建党节,从1921年到2020年,中国共产党已经带领中国人民走过了99年。

请计算 mod 1921,其中A mod B 表示A除以B的余数。

【答案提交】

这是一道结果填空题,只需将整数提交即可

思路:大整数求余数,求模公式:
(a+b)modn=((amodn)+(bmodn))modn;
(a-b)modn=((amodn)-(bmodn)+n)modn ;
(a*b)modn=(amodn)(bmodn)modn;

源码:

因为问题的关键就是指数N比较大,如果能将指数能够降下来,将其转换成对等的表达式,则问题就好解决了。我们看前面求乘积的过程,假定是最简单的情况,N =2,则相当于求(X * X) mod D. 如果利用整数求余数的性质,我们发现他们满足下面的性质:

这个等式的证明可以参照相关的数学材料或者文章后面的补充证明部分。通过这个性质,至少我们可以发现,对于两个数的乘积求余数,我们可以先求一个数的余数,然后再将这个余数乘以另外一个数再求余数。这样就可以求出来两个数乘积的余数。那么,如果对于3个,4个甚至更多的数的乘积求余数呢?我们可以将这个等式扩展一下,对于3个数的乘积,我们可以先求出前面两个数乘积的余数,再和第三个数相乘求。依次类推,重复N次就可以求出N次方的结果。于是,基于这种思路,我们可以写出如下的代码:

import java.math.BigInteger;
import java.util.Scanner;

public class A {

		public static void main(String [] args){
			
			System.out.println(power(7,2020,1921));
		}
		public static long power(long x,long n,long p){
			if(n==0){
				return 1;
			}
			long tmp = x%p;
			for(long i = 0;i<n-1;i++){
				tmp = (x*tmp)%p;
			}
			return tmp;
		}

}

这种方法和前面的思路比起来,有一个进步的地方,就是每次运算的时候都对中间结果求模运算,使得结果都在普通数据类型可以保存的范围内,这样不会需要额外的存储空间。而时间的复杂度主要取决于运算的指数,所以时间复杂度为o(N)。这样我们就找到了一个还不错的解决方法了。

再进一步考虑
前面的办法虽然是已经在一个o(N)的范围了,可是如果N很大的话,我们还是要做一个很大的循环运算。还有没有可能使得我们的方法更加有效率呢?我们求X的N次方,可以根据N的性质做如下的分析:

当N为偶数的情况下:

那么,就有如下的等式成立:

后面这一部分的等式成立是基于模运算的这么一个特性:

当N为奇数的情况下,则有:

那么,结合前面讨论的公式,对奇数情况下求模,则结果为如下等式:

综合前面的两种情况,我们可以发现,当N为偶数时,我们可以求X的平方再取模,如果是奇数的话则要再乘以X,然后取模。这样,一次运算下来,我们就将指数N折半了。按照这个过程,整个过程的时间复杂度可以降低到对数的级别上来。

根据讨论的递归关系,我们可以得出如下递归方式的代码:

public static long power(long x, long n, long p)  
{  
    if(n == 0)  
        return 1;  
  
    long tmp = power((x * x) % p, n / 2, p);  
  
    if(n % 2 != 0)  
        tmp = (tmp * x) % p;  
  
    return tmp;  
}  

将递归版本转换成循环实现的方式的代码如下:

public static long loopPower(long x, long n, long p)  
{  
    x %= p;  
    long tmp = 0;  
  
    while(n > 0)  
    {  
        tmp = (x * x) % p;  
        if(n % 2 != 0)  
            tmp = (tmp * x) % p;  
        n /= 2;  
    }  
  
    return tmp;  
}  

运行得,答案:480

感谢分享的思路

大整数求余数的问题分析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值