学习:欧拉函数

欧拉函数

定义

\(\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}\)

证明

咕咕咕

posted @ 2019-11-22 16:22  loney_s  阅读(213)  评论(0)    收藏  举报