一 。欧拉函数
若a,m互质,≡1(mod m)
1 欧拉函数定义
在数论中,对正整数n,欧拉函数φ(n)是小于或等于n的正整数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为φ函数(由高斯所命名)或是欧拉总计函数(totient function,由西尔维斯特所命名)。
例如φ(8) = 4,因为1,3,5,7均和8互质。
也可以从简化剩余系的角度来解释,简化剩余系(reduced residue system)也称既约剩余系或缩系,是m的完全剩余系中与m互素的数构成的子集,如果模m的一个剩余类里所有数都与m互素,就把它叫做与模m互素的剩余类。在与模m互素的全体剩余类中,从每一个类中各任取一个数作为代表组成的集合,叫做模m的一个简化剩余系。
(1,3,5,7)就构成了8的一个简化剩余系
2 标准分解式
标准分解式:将质因数分解的结果,按照质因数大小,由小到大排列,并将相同质因数的连乘积,以指数形式表示,此种表示法称为标准分解式。
如2020的标准分解式是
3 欧拉函数计算方法
(1)先化为标准分解式形式
(2)再依照下式规则计算
例如:
欧拉函数的性质
-
φ(n) 是积性函数:
即若a⊥b,那么 φ(a⋅b)=φ(a)⋅φ(b)
特别地,若 n 为奇数,则 φ(2n)=φ(n)
原因: 2 为质数,且 φ(2)=1 。
-
对于任意素数 p ,有φ(pk)=pk−1⋅(p−1)
证明: 显然对于从 1 到 pk 的所有数之中,除了pk−1 个 p 的倍数之外,其他的数都与 pk 互素,故 φ(pk)=pk−pk−1=pk−1⋅(p−1)
-
n=∑d∣nφ(d)
表示 n 及其因数的欧拉函数之和等于 n
第一种方法在分解质因数是求出欧拉函数
时间复杂夫O(sqrt(n))
class person {
public:
static int phi(int n) {
int ans = n;
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
};
第二种方法是利用欧拉筛求出1~n的欧拉函数
时间复杂度为O(n)
#include<cstdio>
#include<cmath>
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
#define endl "\n"
#define ll long long
const int N = 1e6 + 7;
const int mod = 998244353;
int prime[N];
bool isprime[N];
int phi[N];
int cnt = 0;
class person {
public:
static void euler(int n) {
memset(isprime, true, sizeof(isprime)); // 先全部标记为素数
isprime[1] = false; // 1不是素数
for (int i = 2; i <= n; ++i) { // i从2循环到n(外层循环)
if (isprime[i]) {
prime[++cnt] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= cnt && i * prime[j] <= n; ++j) {
isprime[i * prime[j]] = false;
if (i % prime[j]) {
phi[i * prime[j]] = phi[i] * phi[prime[j]];
} else {
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
// 最神奇的一句话,如果i整除prime[j],退出循环
// 这样可以保证线性的时间复杂度
}
}
}
};
int main() {
int n;
cin >> n;
if(n==1)
{
cout<<0;
return 0;
}
person::euler(n);
int sum = 3;
for (int i = 2; i <n; i++) {
sum += 2*phi[i];
}
cout << sum;
return 0;
}
[SDOI2008]仪仗队 (nowcoder.com)(题目链接)
二 。欧拉函数扩展
若b>φ(m)即使a,m不互质,a^b≡a^(b%φ(m)+φ(m))(mod m)
引出欧拉降幂公式
求解的问题:
为了求解这个式子a^bmodc,我们可以怎么做?
暴力pow?快速幂?
很显然,当b大到一定程度时,利用pow或者快速幂这样的算法是无法在给定时间内求解的,这时我们引入欧拉降幂算法,这个算法的特点就是降低幂方的值而不影响最终结果,使我们解决问题的时间缩短。
所以当b一定大时采用欧拉降幂来求
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int MAX = 1000100;
ll qmi(ll a, ll b, ll mod) {
ll ans = 1;
a %= mod;
while (b) {
if (b & 1) {
ans = (ans * a) % mod;
}
b >>= 1;
a = (a * a) % mod;
}
return ans;
}
ll Euler(ll x) {
ll Euler = x;
for (ll i = 2; i * i <= x; i++) {
if (x % i == 0) {
Euler = Euler / i * (i - 1);
while (x % i == 0) {
x /= i;
}
}
}
if (x > 1) {
Euler = Euler / x * (x - 1);
}
return Euler;
}
ll eulerDropPow(ll a, char b[], ll c) {
ll EulerNumbers = Euler(c);
ll sum = 0;
for (ll i = 0, len = strlen(b); i < len; ++i) {
sum = (sum * 10 + b[i] - '0') % EulerNumbers;
}
sum += EulerNumbers;
return qmi(a, sum, c);
}
int main() {
ll a, c;
char b[MAX];
while (~scanf("%lld%s%lld", &a, b, &c)) {
printf("%lld\n", eulerDropPow(a, b, c));
}
return 0;
}