补题的时候遇到了一道欧拉降幂,发现欧拉降幂可以总结为一下几点:
1.欧拉降幂的三个式子中,第一个可以永远不用,因为可以转化为第三个式子,推导如下:
2.②式和③式还是要区分的,当
b
<
φ
(
p
)
b < φ(p)
b<φ(p)的时候,第三个式子是不成立的,这个时候就让他等于第一个式子就可以了。(这句话不懂可以直接看下面的图)
3.总结后的欧拉降幂图:
那么通常这个b都非常非常大,因此我们使用按位读入边读边模的技巧,注意这里模的是
φ
(
p
)
φ(p)
φ(p),该模就模(因为无论b和
φ
(
p
)
φ(p)
φ(p)的大小关系如何,都是要有
b
m
o
d
φ
(
p
)
b mod φ(p)
bmodφ(p)的),记得标记一下,待会要不要加上
φ
(
p
)
φ(p)
φ(p),最后用快速幂算答案的时候再模
p
p
p。下面的一段代码十分方便理解这段话:
洛谷P5091
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int qpow(int a, int b, int mod)//快速幂
{
int res = 1;
while(b)
{
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
int getphi(int a)//求欧拉函数
{
int res = a;
for(int i=2;i<=a/i;++i)
{
if(a % i == 0)
{
res = res / i * (i-1);
while(a % i == 0) a /= i;
}
}
if(a > 1) res = res / a * (a-1);
return res;
}
signed main()
{
int a,b,m;
scanf("%lld%lld",&a,&m);
int phim = getphi(m);
char c;
bool flag = 0;
while(!isdigit(c = getchar()));//边读入边取模
for(;isdigit(c);c = getchar())
{
b = b * 10 + c - '0';
if(b >= phim)
{
flag = true;//标记一下,表示要使用第三个式子,也就是说待会还要再+phim
b %= phim;
}
}
if(b < phim) b %= phim;//这句话个人觉得还是加上比较好,因为有的时候虽然b<φ(p),但是b依然非常大,加上这句话这个我觉得要保险一点,这也是上面欧拉降幂图示的写法
if(flag) b += phim;//b > φ(p)的时候才+φ(p)
int ans = qpow(a,b,m);
printf("%lld",ans);
}
再补充一句,注意上面是如何边读入边取模的,这个我之前还确实不知道,因为大数用python3习惯了,但是这题用python3会T的。
补充题目:
幂塔个位数的计算
这题可以找规律(但是比较难找,而且毕竟不是通解),所以还是学会欧拉降幂比较好。