引入
一个问题:求a的b次方对m取模的结果
思考1
好像很简单,快速幂就可以了
如果b是10的20000000次方呢
emmmmm这是不可做题吧
一定要把b缩小,怎么缩小呢
欧拉定理
φ(n)表示小于等于n的正整数中与n互质的数的个数(欧拉函数)。
a与m互质时,a^φ(m)%m=1
扩展欧拉定理
该定理不需要a与m互质
b>=φ(m)时,a^b%m=a^(b%φ(m)+φ(m))%m
思考2
这样就可以缩小b了,但是如果m是10的12次方呢,好像取模之前就会爆long long了
难道要写高精度?高精度也要超时啊QwQ,怎么办
龟速乘
这是什么玩意,好吧,它可以让我们解决乘起来爆long long的问题
它是怎么实现的呢,用加法代替乘法,和快速幂相似的是,快速幂每次会以平方的倍数增大,而龟速乘是翻倍增大
ac代码
来放一下具体的代码吧
#include<bits/stdc++.h>
using namespace std;
long long phi(long long n)
{
long long res=n;
for(long long i=2;i*i<=n;i++)
{
if(n%i==0)
{
res-=res/i;
while(n%i==0)n/=i;
}
}
if(n>1)res-=res/n;
return res;
}
//欧拉函数
long long mul(long long x,long long y,long long mod)
{
long long ans=0;
while(y!=0)
{
if(y%2)ans+=x,ans%=mod;
x=x+x,x%=mod,y>>=1;
}
return ans;
}
//加法代替乘法
long long pow(long long x,long long y,long long mod)
{
long long ans=1;
while(y!=0)
{
if(y%2)ans=mul(ans,x,mod);
x=mul(x,x,mod),y>>=1;
}
return ans;
}
//龟速乘
long long a,b,m,x,ans=1,flg=0;
char c;
int main()
{
scanf("%lld%lld",&a,&m),x=phi(m);
while(!isdigit(c=getchar()));
for(;isdigit(c);c=getchar())
{
b=b*10+c-'0';
if(b>=x)b%=x,flg=1;
}
if(flg)b+=x;
//以上是使用拓展欧拉定理来缩小b
printf("%lld",pow(a,b,m));
return 0;
}