学习:欧拉函数
欧拉函数
定义
\(\varphi(x)\)=小于等于x的与x互质的数
\(\varphi(x)=\sum_{i=1}^{x}[gcd(x,i)==1]\)
特殊的\(\varphi(1)=1\)
怎样求
-
\(O(n*log_n)\)
枚举每一个小于等于n的i,
之后暴力求\(gcd(n,i)\)。
但是过于暴力
-
\(O(n)\)
考虑找到属于n的每一个质因数
之后对这些质因数进行容斥
质因数最多有\(log_n\)个
\(2^{log_n}\)就是n
设n的质因数为\(p_1,p_2,p_3...p_m\)
\(\varphi(n)=n-\sum_{i=1}^{m}\frac{n}{p_i}+\sum_{i=1}^{m}\sum_{j=i+1}^{m}\frac{n}{p_i*p_j}......\)
-
\(O(\sqrt{n})\)
我们将容斥的式子化简一下就得到了\(\varphi\)的通项公式
\(\varphi(n)=n*(1-\frac{1}{p_1})*(1-\frac{1}{p_2})......\)
\(\varphi(n)=n*\prod_{i=1}^{m}\frac{p_i-1}{p_i}\)
之后我们可以很容易得到欧拉函数是积性函数这个结论
我们也可用这个式子来敲代码即可
-
更好
\(\varphi\)为积性函数
\(\varphi(n)=\varphi(x)*\varphi(n/x)[gcd(x,\frac{n}{x})==1]\)
可以发现当\(n=p^k\),\(\varphi(n)=p^{k-1}*(p-1)\),\(p\)为质数
由此出发,对于\(\varphi(n)\),
\(\varphi(n)=p^{k-1}*(p-1)*\varphi(\frac{n}{p^k})\)
也就是说我们只需要知道\(p,p^k,p^{k-1}*(p-1),\varphi(\frac{n}{p^k})\)
时间复杂度笔者也会不算 -
\(O(n)\)线性筛
我们可以直接在做欧拉筛的时候,
顺便找到\(p,p^k\)
对于\(p^{k-1}*(p-1),\varphi(\frac{n}{p^k})\)我们可以处理出一张表
代码
-
\(O(\sqrt{n})\)
#include<iostream> using namespace std; long long n; long long ans; int main() { ios::sync_with_stdio(false); while(1) { cin>>n; ans=n; if(!n) break; for(int i=2;i*i<=n;i++) { if(n%i==0) { ans-=ans/i; while(!(n%i)) { n/=i; } } } if(n>1) { ans-=ans/n; } cout<<ans<<'\n'; } return 0; } -
更好(其实可以用数组来打表,但是为了适用性更好,所以直接使用map)
#include<iostream> #include<map> using namespace std; long long n; map<long long,long long> m; long long solve(long long x) { long long now=x; if(m[x]) return m[x]; for(int i=2;i*i<=x;i++) { if(x%i==0) { long long t=1; while(!(x%i)) { x/=i; t*=i; } t/=i; m[now]=t*(i-1); m[now]=m[now]*solve(now/(t*i)); return m[now]; } } m[x]=x-1; return m[x]; } int main() { ios::sync_with_stdio(false); m[1]=1; while(1) { cin>>n; if(!n) break; cout<<solve(n)<<'\n'; } return 0; } -
线性筛
#include<iostream> using namespace std; long long n; long long phi[1000005]; bool vis[1000005]; long long prime[1000005]; int lenp; void varphi(long long n) { phi[1]=1; for(int i=2;i<=n;i++) { if(!vis[i]) { prime[++lenp]=i; phi[i]=i-1; } for(int j=1;j<=lenp&&prime[j]*i<=n;j++) { vis[prime[j]*i]=1; if(i%prime[j]==0) { phi[i*prime[j]]=prime[j]*phi[i]; break; } else { phi[i*prime[j]]=phi[i]*phi[prime[j]]; } } } } int main() { varphi(1000000); return 0; }
欧拉定理
内容
\(a^c=\begin{cases}a^{c\%\varphi(m)} &(gcd(a,m)==1)\\a^c &(gcd(a,b)\neq1,c<\varphi(m))\\a^{c\%\varphi(m)+\varphi(m)}&(gcd(a,b)\neq1,c\geq\varphi(m))\end{cases}\)
证明
咕咕咕

浙公网安备 33010602011771号