[算法学习记录] 快速幂、乘法逆元

今天刚好学了这两个东西,就把它们放在一起说吧。

快速幂

快速幂是一种用来计算幂运算的算法,该算法适用于精确计算整数幂。
该算法的主要思想就是将指数b分解为二进制形式,并利用幂的平方性质来减少计算次数。
实现方法如下:

  1. 初始化结果为一res=1;
  2. 不断将指数二分,如果指数(b)为奇数,在把基数(a)平方的同时也要让结果乘基数(因为奇数在二分过程中会丢失一部分);
  3. 不管初始情况下指数为奇数还是偶数,经过若干次的二分后,指数一定会变成 1,所以最后结果就是res。
    代码如下(以星码 【模板】快速幂为例):
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll a, b, c;

ll qmi(ll x, ll y, ll z)
{
	ll res = 1;
	while(b)
	{
		if(b & 1 == 1) res = res * a % c;
		//检查b是否为奇数,如果是奇数,res乘以a,每次计算,b除以2并向下取整,在此过程中,奇数会丢失一项 ,所以res要乘上a 
		a = a * a % c; 
		//如果b是奇数,就把a变成a的平方 
		b >>= 1;
		//a变成a的平方,b就要除以2并向下取整 
	}
	return res;
}
//快速幂函数 
void solve()
{
	int t;cin >> t;
	while(t--)
	{
		cin >> a >> b >> c;
		cout << qmi(a, b, c) <<"\n";
	}
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

乘法逆元

由于计算机的数字存储方式的限制,在计算机中进行分数运算极其困难,所以人们就发明了乘法逆元,用来表示一个整数的倒数,以此来进行精确的分数计算。
我们可以用费马小定理来求解一个数的逆元。
给定一个指数p和任意整数x,则有:

\[x^p-1 \equiv 1(modp) \]

等式两边同除以x,有:

\[x^p-2\equiv x^-1(modp) \]

因此,当模数p为质数时,x的逆元为x的p-2此方,即:

\[x^-1\equiv x^p-2(modp) \]

如果质数p较大,直接进行计算可能会超时,所以我们可以用快速幂算法来优化时间复杂度。
代码示例如下(以星码 【模板】乘法逆元为例):

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll a, b, c, q, p = 998244353;

ll qmi(ll x,ll y)
{
	ll res = 1;
	while(y)
	{
		if(y&1) res =res * x % p;
		
		x = x * x % p;
		y >>= 1; 
	}
	return res;
}
//利用快速幂来优化逆元计算的时间复杂度整数x对于模数(p,为质数)的逆元为x的p-2次幂
ll inv(ll x) { return qmi(x, p - 2); }
//计算逆元
void solve()
{
	int t;cin >> t;
	while(t--)
	{
		cin >> a >> b >> c >> q;
		while(q--)
		{
			int x;cin >> x;
			cout << (((a * x % p) + b) % p * inv(c * x % p)) % p << "\n";
			//根据题目所给算式计算,a*b的模就等于对a,b各自取模的积,这样可以避免因中间量过大而引起的数据溢出
		} 
	}
}

int main()
{
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int _ = 1;
	while(_--)solve();
	return 0;
}

posted @ 2025-03-23 21:08  林克还是克林  阅读(158)  评论(0)    收藏  举报