费马定理在数论中推理其他结论还是会经常用到了,欧拉定理可以单独出题。欧拉定理其实也算是包含了费马定理,或者说费马定理是欧拉定理中的一种特殊情况。
费马小定理
设 p 是素数, a 是任意整数且 a ≢ 0 ( m o d p ) , 则 a p − 1 ≡ 1 ( m o d p ) 设p是素数,a是任意整数且a\not \equiv0(mod\ \ p),\ \ 则\\ a^{p-1}\equiv 1 (mod\ \ p) 设p是素数,a是任意整数且a≡0(mod p), 则ap−1≡1(mod p)
欧拉函数
在1与m之间且与m互素的整数的个数被称为欧拉函数,记为φ(m)
m
=
p
1
a
1
p
2
a
2
.
.
.
p
n
a
n
m = p_1^{a_1}p_2^{a_2}...p_n^{a_n}
m=p1a1p2a2...pnan
与点m互素的个数是m减去m的约数以及约数的倍数
但是这些倍数会有重合的一部分,这些重合的部分要加上,但是加上的这些有一部分仍然是重合与其他区块的。
根据容斥原理
m
−
m
p
1
−
m
p
2
−
.
.
.
+
m
p
1
p
2
+
.
.
.
−
m
p
1
p
2
p
3
−
.
.
.
m - \frac{m}{p_1} - \frac{m}{p_2}-...+ \frac{m}{p_1p_2}+... - \frac{m}{p_1p_2p_3}-...
m−p1m−p2m−...+p1p2m+...−p1p2p3m−...
我们可以发现
m
(
1
−
1
p
1
)
(
1
−
1
p
2
)
.
.
.
(
1
−
1
p
n
)
m(1-\frac{1}{p_1})(1-\frac{1}{p_2})...(1 - \frac{1}{p_n})
m(1−p11)(1−p21)...(1−pn1)
的展开式为上式
C++
#include <iostream>
using namespace std;
int solve(int m)
{
int res = m;
for (int i = 2; i <= m / i + 1; i++)
{
if (m % i == 0)
{
res = res / i * (i - 1);
while (m % i == 0) m /= i;
}
}
if (m > 1) res = res / m * (m - 1);
return res;
}
int main()
{
int n;
cin >> n;
while (n--)
{
int m;
cin >> m;
cout << solve(m) << endl;
}
return 0;
}
欧拉筛求欧拉函数
代码如下讲解在代码后面
C++
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int prime[N], cnt;
bool st[N];
int euler[N];
void get_eulers(int n)
{
euler[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!st[i])
{
prime[cnt++] = i;
euler[i] = i - 1; // 如果i为质数,其欧拉函数为i - 1
}
for (int j = 0; prime[j] <= n / i; j++)
{
st[prime[j] * i] = true;
if (i % prime[j] == 0)
{
euler[prime[j] * i] = prime[j] * euler[i];
break;
}
euler[prime[j] * i] = euler[i] * (prime[j] - 1);
// euler[prime[j] * i] = prime[j] * euler[i] * (1 - 1 / prime[j]);
}
}
}
int main()
{
int n;
cin >> n;
get_eulers(n);
long long res = 0;
for (int i = 1; i <= n; i++)
{
res += euler[i];
}
cout << res << endl;
return 0;
}
当一个数n
是质数时,其欧拉函数为n-1
当i%prime[j]==0
时,说明i可以用prime[j]表示出来,根据求解欧拉函数的公式
一个数的欧拉函数只与其所有公约数的大小以及这个数本身的大小有关,与公约数的幂次无关。由于i%prime[j]==0
,i
的公约数能表示出prime[j]
,因此prime[j] * i
的欧拉函数与i
的关系为相差prime[j]
此时 euler[prime[j] * i] = euler[i] * prime[j]
其他情况下,i
不能表示出prime[j]
,那么在求prime[j] * i
的欧拉函数不仅要乘上prime[j]
,而且要在公式最后面乘上
(1-1/prime[j])
前后新乘上的两部分可以合并转换为(prime[j] - 1)
i * prime[j]
的欧拉函数为euler[prime[j] * i] = euler[i] * (prime[j] - 1)