今天刚好学了这两个东西,就把它们放在一起说吧。
快速幂
快速幂是一种用来计算幂运算的算法,该算法适用于精确计算整数幂。
该算法的主要思想就是将指数b分解为二进制形式,并利用幂的平方性质来减少计算次数。
实现方法如下:
- 初始化结果为一res=1;
- 不断将指数二分,如果指数(b)为奇数,在把基数(a)平方的同时也要让结果乘基数(因为奇数在二分过程中会丢失一部分);
- 不管初始情况下指数为奇数还是偶数,经过若干次的二分后,指数一定会变成 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;
}