欧拉函数

定义

  • 对于一个数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()
{
//	freopen("group.in","r",stdin);
//	freopen("group.out","w",stdout);
	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;
}
posted @ 2024-10-01 21:34  all_for_god  阅读(5)  评论(0编辑  收藏  举报