快速幂算法(理解快速幂只需两道题)

重点看代码注释

题目 2088: [蓝桥杯]快速幂

时间限制: 1Sec 内存限制: 128MB
题目描述
给定A, B, P,求(A^B) mod P。
输入
输入共一行。
第一行有三个数,N, M, P。
输出
输出共一行,表示所求。

共10组数据
对100%的数据,A, B为long long范围内的非负整数,P为int内的非负整数。

样例输入
2 5 3
样例输出
2


C++代码如下:

#include <iostream>
using namespace std;
typedef long long ll;//用宏定义:#define ll long long
int mod;//全局变量,省去传参。
ll Power(ll base,ll pow);
int main()
{
	ll n,m;
	cin >> n >> m;
	cin >> mod;
	//这句代码一定要写上,在某的博客上没有这句活的,这个文章后面会讲
	n %= mod;//重点//将n化简,降低时间复杂度//由取模运算可知底数都要取一次模 
	cout << Power(n,m);
	return 0;
}
ll Power(ll base,ll power){
	ll result = 1;
	while (power){
		if (power & 1){
			result = (result * base) % mod;//取模是因为最后幂次为1时,还要取模,不论奇数还是偶数,除以二的过程中都会为1。 
		}
		power >>= 1;
		base = (base * base) % mod;//每一次乘之后,都要取模 
	}
	return result;
}

用C语言写代码如下:

#include <stdio.h>
#define ll long long
int main()
{
	ll base,power;//快速幂的目的是解决大数字,所以防止溢出,直接用long long
	int mod;
	ll result = 1;//result是最后的余数,即所求的数
	scanf("%lld %lld %d",&base,&power,&mod);
	base %= mod;//将base化简,降低时间复杂度
	while (power){ //logn,极大的降低时间复杂度
		if (power % 2 == 1){ //如果power是奇数,最后还要算一次base%mod
			result = (result * base) % mod;
		}
		power >>= 1;//改为位运算,速度更快//相当于power/=2;
		base = (base * base) % mod;
	}
	printf("%lld\n",result);
	return 0;
}

分元宵(传送)

题目描述
毕竟是元宵节,晚上还是要吃几个元宵。 Etéreo 家可是个大家庭,元宵的数量,甚至是餐具的数量,都多的惊人。现在,爱数学的 Etéreo 又来问你有趣的数学题了,快来秒掉它! Etéreo 家里有 \varsigmaς 种元宵馅, \varthetaϑ 种元宵皮,每个元宵可以选择任意一种元宵馅和任意一种元宵皮。同时有 \varpiϖ 张桌子,每张桌子上放了 \varrhoϱ 只碗,每只碗能放一只元宵。每只碗都要装一只元宵。Etéreo 会告诉你 \varsigma, \vartheta, \varpi, \varrhoς,ϑ,ϖ,ϱ 的值,想请问你有多少种装元宵的方式。答案对 \LambdaΛ 取模。
两种方式被认为是不同的当且仅当至少有一只碗存在于两种方式的同一个位置但是里面有至少一个元宵不同。
两个元宵被认为是不同的当且仅当元宵馅不同或者元宵皮不同。
碗和桌子都是有编号的,但是你不能改变碗或桌子的编号。
你可以认为碗和桌子都是固定的,你只能改变元宵的种类和位置。

输入描述:
输入共一行,五个整数 \varsigma, \vartheta, \varpi, \varrho, \Lambdaς,ϑ,ϖ,ϱ,Λ ,意义同题目描述。
输出描述:
每行一个整数,表示答案。
备注:
0≤ς,ϑ≤10^18
0≤ϖ,ϱ≤10^6
1≤Λ≤1,000,000,007


问题分析:
已知有 A 种 元宵馅,B 种元宵皮;
所以 我们可以认为 有Q = A * B 种 元宵;
有 C 张桌子 每张桌子上有 D 个碗;
所以 我们可以认为 一共有W = C * D 种位置;
两种不同方式的鉴定 是 至少存在一个相同的位置 上面的 元宵 是不同的;
我们可以认为每个位置 都有Q种选择 所以最后的答案 应该是 Q^W 然后要取模,就用快速幂。

在学习C++中,我们用到cmath或者循环计算指数幂。
但cmath中pow效率没循环高,循环效率也不高,计算一个数字的n次幂,就需要循环n次,复杂度为O(n)。

注:在做一些联系现实世界的题时,往往要考虑数据取特殊值,与实际联系起来。
如:这一题,当元宵馅和元宵皮为0时,在代码中,运行结果与事实符合,为0;当桌子和碗为0时,在代码中,运行结果与事实不符合,为1;所以加了判断条件num2 == 0

C++代码如下:

#include <iostream>
#include <cmath>
using namespace std;
#define ll long long

int main()
{
	ll a,b,c,d,e;
	scanf("%lld %lld %lld %lld %lld",&a,&b,&c,&d,&e);
	ll num1 = (a % e) * (b % e) % e;//相当于对a * b取模,也就是底数取模
	ll num2 = c * d;
	ll result = 1;
	//num1 %= e;//前面已经除过了,再出没意义//但有些题解上写的有,可能是习惯吧.
    if (num2 == 0){
        printf("0");//要结合实际(特殊)情况,当没桌子或碗时
    } else {
	    while (num2){
		    if (num2 & 1){
			    result = (result * num1) % e;
		    }
		    num1 = (num1 * num1) % e;
		    num2 >>= 1;
	    }
        printf("%lld\n",result);
    }
	return 0;
}

总结:

1.快速幂

快速幂的目的是解决大数字,所以防止溢出,直接用long long。

快速幂的模板如下:

long long mod;//这里为全局变量 
long long Quiet_Power(long long base,long long power)
{
	long long result = 1;//result即是所求的数
	base %= mod;//一定要写上,不然有些题过不了 //将base化简,降低时间复杂度,即为边乘边取模的过程实现之一。
	while (power){
		if (power & 1){ //此处等价于if(power%2==1)//属于位运算,速度更快
			result = (result * base) % mod;//也可以写成 result = result * base % mod
		}
		base = (base * base) % mod;
		power >>= 1; //此处等价于power=power/2 //属于位运算,速度更快
	} 
	return result;
} 

这就是快速幂。

用JAVA的代码如下:
思路:java中,没longlong类型,用大数处理

//调用BigInteger的两个方法的第一个加个括号,规范化!
import java.util.Scanner;
import java.math.BigInteger;
public class A {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        BigInteger base = sc.nextBigInteger();
        BigInteger power = sc.nextBigInteger();
        BigInteger mod = sc.nextBigInteger();
        BigInteger result = BigInteger.ONE;
        base = base.mod(mod);
        //思维不要苟安一偶
        //power > 0 || power != 0
        while (power.compareTo(BigInteger.ZERO) != 0){
        //power % 2 != 0 || power % 2 == 1 判断奇偶数
            if ((power.mod(BigInteger.TWO).compareTo(BigInteger.ONE) == 0))//注意:这里是判断奇偶数的,是取余mod,不是divide,之前就搞错了。
            {
                result = (result.multiply(base)).mod(mod);
            }
            base = (base.multiply(base)).mod(mod);
            power = power.divide(BigInteger.TWO);
        }
        System.out.println(result);
        sc.close();
    }
}

2.取模运算

“取模”运算的运算法则:

1. (a + b) % p = (a % p + b % p) % p

2. (a - b) % p = (a % p - b % p ) % p

3. (a * b) % p = (a % p * b % p) % p

重点了解第三个式子,可以得到多个因子连续的乘积取模的结果等于每个因子取模后的乘积再取模的结果。
**误区:**普通方法是用等号前面的,快速幂是边计算边取模。
在学习快速幂时,我理解为等号前面是自己计算时的过程,后面是计算机计算取模时的过程。

3.为啥在while之前,加上base %= mod

边乘边取模的过程

参考资料:
1.小白入门(但这篇文章有瑕疵,在我文章中已解决,总体可以,适合了解,不适合做题)勿喷,纯属个人看法。

2.了解位运算(传送)

3.分元宵更详解(传送)

4.BigInteger详解(常用方法基本都有,就是排版不行,有时间我写一期)

哎哎,别先着急传送啊,喜欢的😍点个赞再走呗❤️

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值