欧拉函数及欧拉定理

欧拉函数

定义

  • 对于一个数n,\(\varphi(n)\)是小于n的所有正整数中与n互质的数的个数
  • 定义式:$\varphi(n)=n*\frac{p_{1}-1}{p_{1}} * \frac{p_{2}-1}{p_{2}} \cdots $
    \(p_{i}\)是n的所有质因子 注意:一种质因子只能乘一次
  • 定义域:\(N^{*}\)

性质

  1. \(\varphi(1)=1\)
  2. 对于一个质数p,\(\varphi(p)=p-1\)
  3. 如果p、q为质数,则有\(\varphi(p * q)=\varphi(p) * \varphi(p)=(p-1) * (q-1)\),即欧拉函数是积性的
  4. 如果p为质数,则有\(\varphi(p^{k})=p^{k}-p^{k-1}\)
  5. 对于正整数n,有\(\sum_{h|n}\varphi(h)=n\)
  6. 对于互质的两个数a、b,\(\varphi(a * b)=\varphi(a) * \varphi(b)\)
  7. 如果\(a|b\),则\(\varphi(a * b)=\varphi(b) * a\)

求解

单个欧拉函数的求解

  • 直接使用定义式暴力枚举每个质因子,时间复杂度\(O(\sqrt{n})\)
cin>>n;
int res=n;
for(int i=2;i*i<=n;i++)
{
	if(!(n%i))
	{
		res=res*(i-1)/i;
		while(!(n%i)) n/=i;
	}
}
if(n>1) res=res*(n-1)/n;//注意,这一行必须加,这里证明还有一个质因数没算

欧拉筛线性求欧拉函数

  • 通过欧拉筛,筛出质数后运用性质5、6求出线性范围内的所有数的欧拉函数
vector <int> q;
int tot=0;
cin>>n;//范围
vis[0]=vis[1]=1;
for(int i=2;i<=n;i++)
{
	if(!vis[i])//如果是质数,则初始化其欧拉函数并将其压入q中
	{
		phi[i]=i-1;
		q.push_back(i),tot++;
	}
	for(int j=0;j<tot&&i*q[j]<=n;j++)//枚举所有质数
	{
		vis[i*q[j]]=1;
		if(!i%q[j])
		{
			phi[i*q[j]]=phi[i]*q[j];//性质6
			break;//i已经包含了q[j]的所有质因子,再继续枚举一定全是重复的
		}
		else phi[i*q[j]]=phi[i]*phi[q[j]];//性质5.由于q[j]是质数,所以如果i不整除q[j],因此二者一定互质
	}
}

例题

  • Mr.Hu 最近在研究等比数列,即形如:
    $ a^{0} , a^{1} , a^{2} , \cdots , a^{n} , \cdots $
    现在,Mr.Hu 想知道,对于给定的非负整数 a,上面这个无穷数列在模 mod 意义下有多少项是本质不同的。(保证 gcd(a, mod) = 1)。
    对于 30% 的数据,0 ≤ a ≤ \(10^{3}\),1 ≤ mod ≤ \(10^{3}\)
    对于 100% 的数据,0 ≤ a ≤ 2 × \(10^{9}\),1 ≤ mod ≤ 2 × \(10^{9}\),且保证 gcd(a, mod) = 1,1 ≤ T ≤ 100。
  • \(a^{x}\equiv 1 (mod p)\),则显然再继续乘是循环的,因此求出最小的x后,由于指数是从0开始的,因此就有x种不同的答案
    由于欧拉定理\(a^{\varphi(p)}\equiv 1(mod p)\),因此在\(x=\varphi(p)\)时是一定有解的
    现在的问题就是如何去由这个特解去求最小解
    这里有一个很暴力的做法,就是去枚举\(\varphi(p)\)的所有因数。暴力去check这个因数是否合法
    由于因数最多只有$ \sqrt{p} $个,因此时间复杂度为 $ O ( T\sqrt{p}log_{p} ) $
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ksm(ll x,ll k,ll p)
{
	ll res=1;
	while(k)
	{
		if(k&1) res=res*x%p;
		k>>=1;x=x*x;x%=p;
	}
	return res;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		ll a,p,phi=0,n;
		scanf("%lld%lld",&a,&p);
		phi=n=p;
		for(ll i=2;i<=sqrt(n)+1;i++)
		{
			if(!(n%i))
			{
				phi=phi*(i-1)/i;
				while(!(n%i)) n/=i;
			}
		}
		if(n>1) phi=phi*(n-1)/n,n=1;
		ll res=phi;bool fo=0;
		for(ll i=1;i*i<=phi;i++)
		{
			if(!(phi%i)) 
			if(ksm(a,i,p)==1)
			{
				res=i;break;
			}
			else if(ksm(a,phi/i,p)==1) res=phi/i;  //这里取了个巧,同时算大和小的因数
		}
		if(!fo) printf("%lld\n",res);
	}
	return 0;
}

欧拉定理

\(\gcd(a,p)=1\),则
$$
a^c\equiv a^{c\bmod \varphi(p)}\pmod p
$$
\(p\) 为质数时,显然有 \(a^{p-1}=1\),即费马小定理。也就是说费马小定理是欧拉定理的特殊情况。

扩展欧拉定理

\[ a^c\equiv\begin{cases}a^{c\bmod \varphi(p)} &\gcd(a,m)=1\\ a^c &\gcd(a,m)\neq 1 \land c< \varphi(p)\\ a^{c\bmod \varphi(p)+\varphi(p)} &\gcd(a,m)\neq 1 \land c\ge \varphi(p) \end{cases} \pmod p \]

欧拉反演(?)

\[n=\sum_{h|n}\varphi (h) \]

\[gcd(a,b)=\sum_{h|gcd(a,b)}\varphi(h)=\sum_d[d|a][d|b]\varphi (d) \]

这当然只是一种特殊的形式,但是这个东西在处理和式的时候很常用。因为这个欧拉函数的 \(\sum\) 大概率可以提到前面去。

P2398 GCD SUM

\[\sum_i^n\sum_j^n gcd(i,j) \]

转化一下就好了。

\[\begin{aligned} 原式 & =\sum_i\sum_j\sum_d[d|i][d|j]\varphi(d) \\ & = \sum_d\varphi(d)\sum_i\sum_j[d|i][d|j]\\ & = \sum_d\varphi(d)\left \lfloor \frac{n}{d} \right \rfloor^2\\ \end{aligned} \]

然后就可以暴力了。

code

这里没有用线性筛去筛欧拉函数,而是暴力,因为能过。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
long long phi[100005];
long long ans=0;
void getphi(int n)
{
	for(int i=1;i<=n;i++) phi[i]=i;
	for(int i=2;i<=n;i++)
	if(phi[i]==i)
	for(int j=i;j<=n;j+=i) phi[j]=phi[j]*(i-1)/i;
}

int main()
{
	long long n;cin>>n;
	getphi(n);
	for(int i=1;i<=n;i++)
	{
		ans+=1ll*phi[i]*(n/i)*(n/i);
	}
	cout<<ans<<endl;
}

裴蜀定理

对于不全为0的整数 \(a,b\)

  1. \(\forall x,y\qquad gcd(a,b)|ax+by\)
  2. \(\exists x,y\qquad ax+by=gcd(a,b)\)

逆定理:
\(d>0\)\(a,b\) 的公因数,使得 \(ax+by=d\),则 \(d=gcd(a,b)\)
特别的,若存在 \(ax+by=1\),则 \(a,b\) 互质。

在多个整数的情况下,裴蜀定理及其逆定理仍然成立。

进一步的,对于 \(C=ab-a-b\),有
0可以被表示。
\(C\) 不能被表示。
负数不能被表示。
大于 \(C\) 的数可以被表示。
大于0小于 \(C\) 的一个数 \(n\)\(C-n\)\(n\) 有且仅有一个可以被表示。

其中对于任意一个整数 \(n\),其可以被表示的定义是存在自然数 \(x,y\) 使得 \(ax+by=n\)

posted @ 2024-10-01 21:34  all_for_god  阅读(91)  评论(0)    收藏  举报