欧拉函数

欧拉函数

\(O(\sqrt n)\)求单个\(\varphi(x)\)的值

上公式:

\[\varphi(n)=n\times \prod_{i=1}^s\frac{p_i-1}{p_i} \]

  • 引理:若\(p\)为质数,则\(\varphi(p^k)=p^k-p^{k-1}\)
    因为与\(p^k\)不互质的只有\(p\)的倍数,而\(p^k\)\(p\)的倍数有\(p^{k-1}\)

由唯一分解定理,\(\varphi(x)\)函数的积性,以及引理可推:

\[\begin{aligned} \varphi(n)&=n\times \prod_{i=1}^s(p_i^{k_i})\\ &=\prod_{i=1}^s(p_i-1)\times p_i^{k_i-1}\\ &=\prod_{i=1}^s{p_i^{k_i}\times(1-\frac{1}{p_i})}\\ &=n\prod_{i=1}^s(1-\frac{1}{p_i}) \end{aligned} \]

il int phi(int x)
{
	int m=sqrt(x+0.5),re=x;
	for(int i=2;i<=m;i++)
    	if(x%i==0) 
	{
    	     re=re/i*(i-1);
    	     while(x%i==0)x/=i;
   	}
	if(x>1) re=re/x*(x-1);
	return re;
}

筛法求\(\varphi(n)\)

il void Euler()
{
	phi[1]=1,isprime[1]=isprime[0]=1;
	for(ri int i(2);i<=N-3;++i)
	{
		if(!isprime[i]) prime[++cnt]=i,phi[i]=i-1;
		for(ri int j(1);j<=cnt&&prime[j]*i<N;++j)
		{
			isprime[prime[j]*i]=true;
			if(i%prime[j]) phi[prime[j]*i]=phi[prime[j]]*phi[i];
			else {phi[prime[j]*i]=prime[j]*phi[i];break;}
		}
	}
//	for(ri int i(1);i<=N-3;++i) printf("%d ",phi[i]);
}

T1 P2158 [SDOI2008] 仪仗队

  • 求队伍整齐时能看到的学生人数。

题解看这篇因为好像只有他和我的结论一样
柿子不会推,但是听说挺板子的,大概:

\[\text{在第}i\text{行第}j\text{列的一个人能被看见当且仅当}\gcd(i,j)=1 \]

\[Ans=2\times\sum_{i=2}^{n-1}\varphi(i)+3 \]

#include<cstdio>
#include<iostream>
#include<algorithm>
#define il inline
#define ri register
#define pc(i) putchar(i)
using namespace std;
const int N=4e4+2;
int n,phi[N],prime[N],cnt,ans=3;
bool isprime[N];
il void pre()
{
    isprime[1]=true,phi[1]=1;
    for(ri int i=2;i<n;++i)
    {
        if(!isprime[i]) prime[++cnt]=i,phi[i]=i-1;
        ans+=phi[i]*2;
        for(ri int j=1;j<=cnt&&i*prime[j]<=n;++j)
        {
            isprime[i*prime[j]]=true;
            if(i%prime[j]) phi[i*prime[j]]=phi[i]*phi[prime[j]]; //n与pi互质
            else {phi[i*prime[j]]=phi[i]*prime[j];break;} //n'包含了n的所有质因子
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    if(n==1) return printf("0"),0; 
	pre(),cout<<ans;
    return 0;
}

T2 P2568 GCD

  • 给定正整数\(n\),求 \(1\le x,y\le n\)\(\gcd(x,y)\)为素数的数对\((x,y)\)有多少对。

参考

\[\begin{align} \because Ans&=\sum_{p\in{prime}}\sum_{i=1}^{n}\sum_{j=1}^{n}[\gcd(i,j)=p]\\ \therefore Ans &= \sum_{p\in{prime}}\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{p}\rfloor}[\gcd(i,j)=1] \\ &={\sum_{p\in{prime}}(\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}(2\times\sum_{j=1}^{i}[\gcd(i,j)=1])-1)}\\ &=\sum_{p\in{prime}}(2\times\sum_{i=1}^{\lfloor\frac{n}{p}\rfloor}\varphi(i)-1) \end{align} \]

#include<cstdio>
#include<iostream>
#include<algorithm>
#define cs const
#define il inline
#define ri register
#define pc(i) putchar(i)
//#define int long long
using namespace std;
cs int N=1e7+3;
int n,prime[664582],cnt,phi[N];
long long ans,sp[N];
bool isprime[N];
il void Euler()
{
	sp[1]=phi[1]=1,isprime[1]=isprime[0]=1;
	for(ri int i(2);i<=n;++i)
	{
		if(!isprime[i]) prime[++cnt]=i,phi[i]=i-1;
		for(ri int j(1);j<=cnt&&prime[j]*i<N;++j)
		{
			isprime[prime[j]*i]=true;
			if(i%prime[j]) phi[prime[j]*i]=phi[prime[j]]*phi[i];
			else {phi[prime[j]*i]=prime[j]*phi[i];break;}
		}
		sp[i]=sp[i-1]+phi[i];
	}
//	for(ri int i(1);i<=100;++i) printf("%d ",phi[i]);pc('\n');
//	for(ri int i(1);i<=100;++i) printf("%d ",sp[i]);
}
signed main()
{
	freopen("gcd.in","r",stdin);
	freopen("gcd.out","w",stdout);
	scanf("%d",&n),Euler();
	for(ri int p(1);p<=cnt;++p)
		ans+=1ll*2*sp[n/prime[p]]-1;
	printf("%lld",ans);
	return 0;
}

T3 [SDOI2012] Longge 的问题

  • \(\sum_{i=1}^{N}\gcd(i,N)\)

参考

显然对于任意\(i \le n\)\(\gcd(i,n)\)一定是 \(n\) 的一个约数

\[\begin{aligned} \sum_{i=1}^{n}\gcd(i,n)&=\sum_{d\mid n}d\times\sum_{i=1}^{n}[\gcd(i,n)=d] \\ &= \sum_{d\mid n}d\times\sum_{i=1}^{\frac{n}{d}}[\gcd(i,\frac{n}{d})=1]\\ &=\sum_{d\mid n}d\times \varphi(\frac{n}{d}) \end{aligned} \]

#include<bits/stdc++.h>
#define cs const
#define il inline
#define ri register
#define pc(i) putchar(i)
#define int long long
using namespace std;
int n,ans=0; 
il void read(int &as)
{
	int f=1;char ch=getchar();as=0;
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') as=(as<<3)+(as<<1)+(ch^48),ch=getchar();as*=f;
}
void wt(int x){if(x<0) x=-x,pc('-');if(x>9) wt(x/10);pc(x%10|48);}
il int phi(int n) {
  int ans=n;
  for(int i=2;i*i<=n;i++)
    if(n%i==0)
	{
      ans=ans/i*(i-1);
      while(n%i==0) n/=i;
    }
  if (n>1) ans=ans/n*(n-1);
  return ans;
}
il int solve(int x)
{
	int re=0,i;
	for(i=1;i*i<x;++i)
		if(x%i==0) re+=i*phi(x/i)+(x/i)*phi(i);
	if(i*i==x) re+=i*phi(i);
	return re;
 } 
signed main()
{
	read(n),wt(solve(n));
	return 0;
}
前面的区域以后再买探索吧

欧拉定理

\[a^b\equiv a^{b\mod \varphi(m)}(\mod m) \]

扩展欧拉定理

\(a,m\in \mathbb Z\)时:

\[\begin{aligned} a^b \equiv \begin{cases} a^b, &b<\varphi(m)\\ a^{b \mod \varphi(m)+\varphi(m)},& b\ge\varphi(m) \end{cases} (\mod m) \end{aligned} \]

证明\(\Huge \to To\space be\space continued\)

T1 【模板】扩展欧拉定理

#include<bits/stdc++.h>
#define cs const
#define il inline
#define ri register
#define pc(i) putchar(i)
#define int long long
using namespace std;
int a,Mod,b,p;
bool flag=0;
il void read(int &as)
{
	as=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9')
	{
		as=(as<<3)+(as<<1)+(ch^48),ch=getchar();
		if(as>=p) as%=p,flag=1;
	}
	as+=(flag?p:0);
}
void wt(int x){if(x<0) pc('-'),x=-x;if(x>9) wt(x/10);pc(x%10|48);}
il int phi(int x)
{
	int m=sqrt(x+0.5),re=x;
	for(int i=2;i<=m;i++)
    	if(x%i==0) 
		{
    		re=re/i*(i-1);
    		while(x%i==0)x/=i;
   		}
	if(x>1) re=re/x*(x-1);
	return re;
}
il int qpow(int base,int power)
{
	int re=1;
	while(power>0)
	{
		if(power&1) (re*=base)%=Mod;
		power>>=1,(base*=base)%=Mod;
	}
	return re%Mod;
}
signed main()
{
	scanf("%lld%lld",&a,&Mod);
	p=phi(Mod),read(b),wt(qpow(a,b));
	return 0;
}
posted @ 2022-10-17 14:39  Bertidurlah  阅读(41)  评论(0)    收藏  举报