第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

感谢分享的思路

大整数求余数的问题分析

目前提供的引用资料中并未提及第十五蓝桥杯Java A的具体真题内容。以下是基于已有信息和其他相关背景知识的回答: ### 关于蓝桥杯比赛 蓝桥杯大赛是一项面向全国高校学生的IT类竞赛活动,其中Java的比赛分为A、B、C三个难度级别[^1]。不同级别的题目设计旨在考察参赛者的算法能力、编程技巧以及逻辑思维水平。 对于2023年的赛事情况,在已知的信息里提到的是第十四蓝桥杯Java B的相关详情[^2],而关于同年举行的Java A具体真题尚未有明确记录被提供出来。通常情况下,较高难度等级(如A)会涉及更加复杂的算法实现和数据结构应用等问题。 尽管如此,可以通过分析往试题来推测可能考查的知识点范围。例如,在第十二蓝桥杯国赛Java B中出现了如下类型的题目:整数范围计算、纯质数判断、完全日期处理等[^3]。这些主题反映了该赛事常考的一些核心领域——包括但不限于基础数学运算、字符串操作、动态规划等方面的内容。 虽然无法直接给出2023年蓝桥杯Java A的确切原题,但可以建议准备此类考试时关注以下几个方面: - **深入理解经典算法**:掌握排序查找方法及其变种形式; - **熟练运用常见数据结构**:链表、栈队列的应用场景熟悉度提升; - **强化复杂问题拆解能力**:面对综合性强的大规模程序设计挑战能够合理分解并逐一攻克难点; 此外还需要注意培养良好的心理素质以便应对实际考场环境下的压力状况。 ```python # 示例代码片段展示如何解决某一类典型问题 def is_prime(n): """ 判断给定数字n是否为素数 """ if n <= 1: return False elif n == 2 or n == 3: return True elif not (n % 6 == 1 or n % 6 == 5): return False sqrt_n = int(pow(n, 0.5)) + 1 for i in range(5, sqrt_n, 6): if n % i == 0 or n % (i + 2) == 0: return False return True ``` 上述函数用于检测某个正整数是不是素数,属于基本却重要的概念之一,在许多竞赛场合下都会有所体现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值