数论学习笔记(欧拉函数)
前言
好久之前学的欧拉函数,现在都快忘光了,写篇笔记加深一下记忆。
前置知识——费马小定理
费马小定理及其应用
逆元:
欧拉函数的定义和一些性质
定义
欧拉函数,定义为从
性质
-
欧拉函数为积性函数,即:
\varphi(nm)=\varphi(n)\varphi(m)\;(\gcd(n,m)=1) 证明如下:
假设数字
n 和数字m 互质,则和mn 互质等价于同时和n 互质和m 互质,假设一个小于等于mn 数字t 与n 和m 的余数数对为(i,j) ,下面证明对于每一个余数数对(i,j) ,其对应的数值t 是唯一且确定的。考虑反证法,假设存在两个数字
l 和r 的余数数对都是(i,j) ,下面统一1 \le l < r \le mn ,则r-l 能被n 和m 整除,也就是被mn 整除,但是有定义可得1\le r-l <mn ,即不存在一个数字和mn 整除,所以假设不成立。因此,和
mn 互质的个数就是和n 互质的个数与和m 互质的个数,即\varphi(mn)=\varphi(n)\varphi(m)\;(\gcd(n,m)=1) 。 -
当
n 为质数时,\varphi(n)=n-1 ,这很显然,因为一个质数n 与从1 到n-1 中的数都互质。 -
\varphi(p^{k})=(p-1)p^{k-1}\;(\text{p is prime}) 证明如下:
\begin{aligned} \varphi(p^k) &= p^k - \sum_{i=1}^p [\gcd(p^k, i) \neq 1] \\ &= p^k - \sum_{i=1}^p [p \mid i] \\ &= p^k - p^{k-1} \\ &= (p-1)p^{k-1} \end{aligned} -
对于任意一个
n ,设n=\prod_{i=1}^{m}{a_i}^{p_i} 则有
\varphi(n)=n\prod_{i=1}^{m}(1-\frac{1}{a_i}) 证明如下:
\begin{aligned} \varphi(n)&=\varphi(\prod_{i=1}^{m}{a_i}^{p_i})\\ &=\prod_{i=1}^{m}\varphi({a_i}^{p_i})\\ &=\prod_{i=1}^{m}(a_i-1){a_i}^{p_i-1}\\ &=\prod_{i=1}^{m}{a_i}^{p_i}(\frac{a_i-1}{a_i})\\ &=\prod_{i=1}^{m}{a_i}^{p_i}\times\prod_{i=1}^{m}(1-\frac{1}{a_i})\\ &=n\prod_{i=1}^{m}(1-\frac{1}{a_i}) \end{aligned} -
对于任意一个
n ,都有n=\sum_{d|n}\varphi(d) 证明如下:
给出
n 个分数\frac{1}{n},\frac{2}{n},\dots,\frac{n}{n} ,将这些分数约分后,我们定义一个函数f(i) 代表以i 为分母且与分子互质的分子小于等于分母的分数的数量,那么很显然n=\sum_{d|n}f(d) ,这个函数f(i) 的定义与欧拉函数的定义一样,所以该式子就为n=\sum_{d|n}\varphi(d) 。如何求欧拉函数?
质因数分解求欧拉函数
我们根据性质
4 可以得出,\varphi(n)=n\prod_{i=1}^{m}(1-\frac{1}{a_i}) ,我们只需按这个模拟即可,时间复杂度为O(\sqrt n) 。Code
int phi(int x){ int ans=x; for(int i=2;i<=sqrt(x);i++){ if(x%i==0)ans=ans/i*(i-1); while(x%i==0)x/=i; } if(x>1)ans=ans/x*(x-1); return ans; }线性筛求欧拉函数
上面的求解方法适合在只需要求解少量的欧拉函数的值,当需要求从
1 到n 中的所有的欧拉函数的值时,就可以用到线性筛求解时间复杂度为O(n) 。
先说结论,对于一个质数
对于第一种
对于第二种
我们惊奇的发现后面的
Code
const int N=1e7+10;
bool f[N];
int phi[N];
vector<int>prime;
void get_phi(int n){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!f[i])prime.push_back(i),phi[i]=i-1;
for(int j=0;j<prime.size()&&prime[j]*i<=n;j++){
f[prime[j]*i]=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);
}
}
}
欧拉定理
与费马小定理的证明类似,下面给出证明。
证明:
将所有的和
对于序列中的每一个数字都和
对于序列中的每一个数字两两不同余,我们考虑反证法。若存在一对数
有了这个性质,就说明将
下面,我们把
也就是:
由于两边都有
扩展欧拉定理
这个定理就不需要
笔者太蒟蒻了不会证,感兴趣的读者可以去了解一下,个人认为只需要记
经典套路
给出一个
根据性质
有一个套路就是将
可在
像这样的有
例题
题目大意
P2158 [SDOI2008] 仪仗队
题目分析
观察可发现,能被看到的人一定是
于是这道题目可以化简成如下式子:
我们固定一个前面
使用线性筛求解,时间复杂度为
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define uint unsigned long long
#define speed ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define pb push_back
const int N=4e4+10;
int n,pri[N],cnt;
int phi[N],ans;
bitset<N>vis;
void init(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i])pri[++cnt]=i,phi[i]=i-1;
for(int j=1;i*pri[j]<=n;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
else phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
}
signed main(){
speed
cin>>n;
if(n==1)return cout<<0,0;
init();
for(int i=1;i<n;i++)ans+=phi[i];
cout<<2*ans+1;
return 0;
}
题目大意
P1390 公约数的和
题目分析
让我们求:
将
直接线性筛求解即可。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define uint unsigned long long
#define speed ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define pii pair<int,int>
#define pb push_back
#define debug cout<<"\n-----------debug-----------\n";
const int N=2e6+10;
int n,phi[N],ans;
bool f[N];
vector<int>prime;
void init(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!f[i])prime.push_back(i),phi[i]=i-1;
for(int j=0;j<prime.size()&&prime[j]*i<=n;j++){
f[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=prime[j]*phi[i];
break;
}
else phi[i*prime[j]]=(prime[j]-1)*phi[i];
}
}
}
signed main(){
speed
cin>>n;
init();
for(int i=1;i<=n;i++){
ans+=phi[i]*(n/i)*(n/i-1)/2;
}
cout<<ans;
return 0;
}
后记
这篇文章写的有些匆忙,如果有地方写错了,欢迎各位大佬指出。