算法——快速幂

原题直通车-SYGZ OJ #790.A^B

题目概览

pCyRRPK.png

最朴素的做法就是for b b b次,每次乘上 a a a

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
	long long a,b,p;
	long long ans=a;
	--b;
	scanf("%lld%lld%lld",&a,&b,&p);
	for (int i=1;i<=b;i++)
	{
		ans*=a;
		ans%=p;
	}
	return 0;
}

但这显然不能过此题,数据范围是1e9的级别,整体是 1 e 9 1 e 9 m o d p 1e9^{1e9} mod p 1e91e9modplong long爆炸)。

pCyWYsH.jpg虽然每次都 m o d mod mod p p p,但还是会爆,高精度时间复杂度太高,无法过。

那么有没有什么优化呢?答案当然是有的。一般快速幂有两种:

分治法

二进制拆分法

本篇介绍二进制拆分法。

大家都知道,求二进制就是不断

vector <int> ans;
int a;
scanf("%d",&a);
while (a)
{
	ans.push_back(a%2);
	a/=2;
}
reverse(ans.begin(),ans.end());

OI-Wiki对此有细致解释。

这个算法的时间复杂度是 O ( l o g n ) O(log n) O(logn)级的。它在于把大任务分解为小任务。由于 n n n log ⁡ 2 n + 1 \log_{2} n +1 log2n+1个二进制位,那么我们只需要知道 a 1 a^{1} a1, a 2 a^{2} a2, a 4 a^{4} a4,…, a 2 log ⁡ n a^{2^{\log n}} a2logn后,就可以通过 log ⁡ n \log n logn次运算解决这个问题。这个序列也很简单:前一个数是后一个数的平方。因此,一个while就可以解决问题。

实现

#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
using namespace std;
long long f(long long a,long long b,long long p)
{
	if (p==1)
	{
		return 0;
	}
	long long res=1;
	while (b)
	{
		if (b%2==1)
		{
			res*=a;
			res%=p;
		}
		a=a*a%p;
		b/=2;
	}
	return res;
}
int main()
{
	long long a,b,p;
	scanf("%lld%lld%lld",&a,&b,&p);
	printf("%lld",f(a,b,p));
	return 0;
}


参考文献

快速幂 - OI Wiki

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值