「学习笔记」光速幂
对于 \(a^b \bmod p\),快速幂单次询问是 \(O(\log b)\) 的。
而有的题目可能要去掉 \(\log\),就用到了光速幂。
令 \(b=k \times s+t\ \ (t \le s)\)
\(a^b \equiv a^{k \times s} \times a^t\ (\bmod\ p)\)
于是就可以预处理出 \(a^1,a^2,\dots,a^s,a^{2s},a^{3s},\dots,a^{\left\lceil{\frac{p}{s}}\right\rceil\times s}\)
当然要 \(\bmod\ p\)
然后 \(a^b \bmod p\) 就可以 \(O(1)\) 查询了。
预处理在 \(s=\sqrt{p}\) 时,时间复杂度最小,为 \(O(\sqrt{p})\)。
根据欧拉定理 \(a^b \equiv a^{b \bmod \phi(p)}\ (\bmod p)\)
可以先把 \(b \bmod \phi(p)\)并且预处理到 \(\phi(p)\) 就可以了,到 \(p\) 只是方便写。
//a^ks*a^t % p (t<=s)
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
const int BL=1<<16; //BL=sqrt(p)
ll B;
ll a,b,p;
ll qp[BL+10][2]; //0:a^t%p 1:a^is%p
ll read()
{
ll x=0;
char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
void init()
{
B=sqrt(p);
qp[0][0]=qp[0][1]=1;
for(int i=1;i<=B;i++)
qp[i][0]=qp[i-1][0]*a%p;
for(int i=1;i<=B;i++)
qp[i][1]=qp[i-1][1]*qp[B][0]%p;
}
ll phi(int x)
{
int res=x;
for(int i=2;i*i<=x;i++)
{
if(x%i==0) res=res/i*(i-1);
while(x%i==0) x/=i;
}
if(x>1) res=res/x*(x-1);
return res;
}
ll qpow(ll b)
{
b%=phi(p);
return qp[b%B][0]*qp[b/B][1]%p;
}
int main()
{
a=read();b=read();p=read();
init();
printf("lld\n",qpow(b));
return 0;
}
$$A\ drop\ of\ tear\ blurs\ memories\ of\ the\ past.$$