洛谷题单指南-进阶数论-P5091 【模板】扩展欧拉定理
原题链接:https://www.luogu.com.cn/problem/P5091
题意解读:求ab % m,b超级大。
解题思路:
大数幂取模问题,通常要用到扩展欧拉定理,下面从欧拉函数开始介绍。
1、欧拉函数
定义:小于等于n的正整数中与n互质的数的个数,叫做n的欧拉函数值,记作φ(n),编程时记为phi(n)
n用整数分解定理可表示为p1a1p2a2...pnan,那么φ(n) = n * (1-1/p1) * (1-1/p2)...*(1-1/pn)
通过容斥原理+归纳法不难证明。
主要性质:
如果n是素数,φ(n) = n - 1
如果a,b互质,φ(a * b) = φ(a) * φ(b)
如果a是素数,b % a == 0,φ(a * b) = a * φ(b)
另外,如果要线性计算1~n所有数的φ(n),可以在欧拉筛的过程中进行递推计算:
for(int i = 2; i <= n; i++)
{
if(!vis[i]) //i是素数
{
p[++cnt] = i; //加入素数表
vis[i] = true; //标记i为合数
phi[i] = i - 1; //计算phi[i]
}
for(int j = 1; j <= cnt; j++)
{
if(i * p[j] > n) break;
vis[i * p[j]] = true; //用最小素因子p[j]标记合数i * p[j]
if(i % p[j] != 0)
{
phi[i * p[j]] = phi[i] * (p[j] - 1);
}
if(i % p[j] == 0)
{
phi[i * p[j]] = phi[i] * p[j];
break;
}
}
}
2、欧拉定理
如果a与n互质,则有aΦ(n) ≡ 1 ( mod n ),其中Φ(n)是关于n的欧拉函数
主要用来简化幂取模问题,如a,n互质,ab % n = ab%Φ(n) % n
3、费马小定理
欧拉定理的特殊情况,n是质数时aΦ(n) = an-1 ≡ 1 ( mod n )
主要用来求逆元,如求a模n的逆元,n是质数,由于an-1 ≡ 1 ( mod n ),a * an-2 ≡ 1 ( mod n ),因此a-1(mod n) = an-2
4、扩展欧拉定理
对于ab % n,a、n不一定互质
当b < Φ(n)时,直接用快速幂计算即可
当b >= Φ(n)时,ab % n = ab%Φ(n)+Φ(n) % n
5、问题分析
先计算Φ(m)
再判断b,如果b < Φ(m),先将b缩小b = b % Φ(m),再用快速幂计算ksm(a, b, m)
如果b >= Φ(m),b = b % Φ(m) + Φ(m),再计算ksm(a, b, m)
100分代码:
#include <bits/stdc++.h>
using namespace std;
int a, m;
string b;
int phi(int x)
{
int res = x;
for(int i = 2; i <= x / i; i++)
{
if(x % i == 0)
{
res = 1ll * res * (i - 1) / i;
while(x % i == 0) x /= i;
}
}
if(x != 1) res = 1ll * res * (x - 1) / x;
return res;
}
int equals(string a, string b)
{
if(a.size() != b.size()) return a.size() - b.size();
for(int i = 0; i < a.size(); i++)
{
if(a[i] != b[i]) return a[i] - b[i];
}
return 0;
}
int ksm(int a, int b, int p)
{
int res = 1;
while(b)
{
if(b & 1) res = 1ll * res * a % p;
a = 1ll * a * a % p;
b >>= 1;
}
return res;
}
int main()
{
cin >> a >> m >> b;
int phim = phi(m);
string phis = ""; //phim的字符串表示
int t = phim;
while(t)
{
phis.push_back('0' + (t % 10));
t /= 10;
}
reverse(phis.begin(), phis.end());
int r = 0;
for(int i = 0; i < b.size(); i++)
{
r = (r * 10ll + b[i] - '0') % phim; //当b < phi(m)时,b%phi(m)=b
}
if(equals(b, phis) >= 0) r = r + phim; //如果b >= phi(m),b = b%phi(m)+phi(m)
cout << ksm(a, r, m) << endl;
return 0;
}
浙公网安备 33010602011771号