欧拉函数和线性欧拉筛

欧拉函数和线性欧拉筛

欧拉函数

定义

\[\phi(n) = \sum_{k=1}^n \delta_{\gcd(k,n),1} \\ \text{(其中δ为克罗内克函数)}\\\delta_{i,j}=\begin{cases} 1\quad(i=j)\\ 0\quad(i\ne j) \end{cases} \]

欧拉函数本质上表示了小于等于 \(n\) 的正整数中\(n\) 互质的个数

注意:欧拉函数在互质时是积性函数非互质时不是积性函数

\[\begin{cases} \phi(a\times b)=\phi(a)\times\phi(b)\quad(gcd(a,b)=1)\\\\ \phi(a\times b)\ne\phi(a)\times\phi(b)\quad(gcd(a,b)\ne1)\\ \end{cases} \]

推论

  • 推论 \(1\):对于质数 \(p\),有:

    \[\phi(p)=p-1 \]

    证明:

    \(1,2,\cdots,p−1\)\(p\) 互质

  • 推论 \(2\):对于质数 \(p\),有:

    \[\phi(p^k)=p^{k-1}\times\phi(p)=p^{k-1}\times(p-1)=p^{k}\times\cfrac{p-1}{p} \]

    证明:

    \([1,p^k]\) 中,与 \(p^k\) 不互质的数均为 \(p\) 的倍数,有 \(\cfrac{p^k}{p}=p^{k-1}\) 个,所以:

    \[\phi(p^k)=p^k-p^{k-1}=p^{k-1}\times(p-1) \]

  • 推论 \(3\):推广至两个不同质数 \(a\)\(b\) ,有:

    \[\phi(a\times b)=\phi(a)\times \phi(b)=a\times b\times \cfrac{a-1}{a}\times \cfrac{b-1}{b} \]

    证明:

    根据推论 \(1\)欧拉函数的积性

    \[\phi(a\times b)=\phi(a)\times\phi(b)=(a-1)\times(b-1)=a\times b\times \cfrac{a-1}{a}\times \cfrac{b-1}{b} \]

  • 推论 \(4\):继续推广,设 \(n=p_1^{k_1}\times p_2^{k_2}\times\cdots\times p_n^{k_n}\)正整数 \(n\) 的标准分解式) ,则有:

    \[\phi(n)=n\times\prod^n_{i=1}\cfrac{p_i-1}{p_i} \]

    证明:

    根据推论 \(2\)欧拉函数的积性

    \[\phi(p_i^{k_i})=p_i^{k_i}\times\cfrac{p_i-1}{p_i} \]

    所以,将所有质因子贡献相乘:

    \[\phi(n)=\prod_{i=1}^{n}\phi(p_i^{k_i})=\prod_{i=1}^{n}(p_i^{k_i}\times\cfrac{p_i-1}{p_i})=n\times\prod^n_{i=1}\cfrac{p_i-1}{p_i} \]

算法实现

根据 推论 \(4\) ,可以发现求欧拉函数重点在\(n\) 的质因数

int ans = n;
for (int i = 2;i * i <= 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); // 处理剩余因子

欧拉函数筛

欧拉函数筛其实是建立在线性质数筛的基础上

这时考虑与线性筛相似的一个问题:如何通过 \(\phi(i)\) 求出 \(\phi(i\times p)\)\(p\) 为小于等于 \(i\) 的质数)

分情况讨论:

  • \(p\mid i\)

    \(i=p^k\times m\quad(\gcd(m,p)=1)\)

    \(\phi(i)\) 展开:

    \[\phi(i)=\phi(p^k\times m)=\phi(p^k)\times \phi(m)=p^{k-1}(p-1)\times\phi(m)\tag1 \]

    \(\phi(i\times p)\) 展开:

    \[\phi(i\times p)=\phi(p^{k+1}\times m)=\phi(p^{k+1})\times\phi(m)=p^k(p-1)\times\phi(m)=p(p^{k-1}(p-1)\times\phi(m))\tag2 \]

    \(1\) 式中的 \(p^{k-1}(p-1)\times\phi(m)=\phi(i)\) 代入 \(2\) 式:

    \[\phi(i\times p)=p\times\phi(i) \]

  • \(p\nmid i\)

    根据欧拉函数的积性

    \[\phi(i\times p)=\phi(i)\times\phi(p)=\phi(i)\times(p-1) \]

int phi[maxn],prime[maxn],cnt = 0; // 统计欧拉函数与质数
bool notprime[maxn]; // (线性质数筛)
phi[1] = 1; 
for(int i = 2;i <= n; ++i) { 
  if(!notprime[i]) prime[++cnt] = i,phi[i] = i - 1; // 质数的情况 (i - 1)
  for(int j = 1;j <= cnt && i * prime[j] <= n; ++j) { // (线性质数筛)
    notprime[i * prime[j]] = 1; // (线性质数筛)
    if(i % prime[j] == 0) { 
    	phi[i * prime[j]] = phi[i] * prime[j]; // p|i
    	break; // (线性质数筛)
    } else phi[i * prime[j]] = phi[i] * (prime[j] - 1); // p !| i
  } 
} 

欧拉定理

\(m\) 为一个正整数,\(a\) 为一个整数,且 \(a\)\(p\) 互质,则:

\[a^{\phi(p)}\equiv 1~(mod~p) \]

\(p\) 为质数时,由**推论 \(1\) **得 \(\phi(p)=p-1\),所以:

\[a^{p-1}\equiv 1~(mod~p)\quad\text{(when p is prime)} \]

这就是费马小定理

扩展欧拉定理

\[a^b=\begin{cases} a^{b\mod \phi(m)}\quad~~~~~~~~~~\gcd(a,m)=1\\ a^b\quad~~~~~~~~~~~~~~~~~~~~~~~~~~ \gcd(a,m)\ne 1,b < \phi(m)\\ a^{(b\mod \phi(m))+\phi(m)}\quad\gcd(a,b)\ne 1,b \ge \phi(m) \end{cases} \]

扩展欧拉定理可以解决 \(a^b\mod p\)指数过大的问题

例题

洛谷 P1405 苦恼的小明

这道题可以采用递归逐步求解平方的做法:

\[a^{b^{c^\cdots}}=a^{(b^{c^\cdots})}=\cdots \]

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1234567;
const int mod0 = 10007;
int n;
int a[maxn + 5];
int phi[maxn];
int prime[maxn], cnt; bool notprime[maxn];
void Getphi(int n) {
	phi[1] = 1;
	for(int i = 2;i <= n; ++i) {
		if(!notprime[i]) prime[++cnt] = i; phi[i] = i - 1;
		for(int j = 1;j <= cnt && i * prime[j] <= n; ++j) {
			notprime[i * prime[j]] = 1;
			if(i % prime[j] == 0) {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			} else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
		}
	}
}
int fastPow(int a,int b,int mod) {
	if (b == 0) return 1;
	if (b == 1) return a % mod;
	int x = fastPow(a,b / 2,mod);
	x = (x % mod * x % mod) % mod;
	if (b % 2 != 0) x = (x % mod * a % mod) % mod;
	return x;
}
int solve(int i,int mod) {
	if (i == n + 1) return 1;
	return fastPow(a[i],solve(i + 1,phi[mod]),mod);
}
int main() {
	memset(notprime,false,sizeof(notprime));
	scanf("%d",&n);
	Getphi(mod0);
	for (int i = 1;i <= n;i ++) scanf("%d",&a[i]);
	printf("%d",solve(1,mod0) % mod0);
  return 0;
} 
posted @ 2025-05-26 23:33  nightmare_lhh  阅读(38)  评论(0)    收藏  举报