P2158 [SDOI2008]仪仗队&&欧拉函数的求法

本文详细介绍了欧拉函数在解决数论问题中的应用,特别是如何利用欧拉函数解决洛谷P2158题。通过转化条件,作者指出能被看见的学生位置与x,y互质等价,从而引出欧拉函数φ(n)的定义。接着,文章提供了两种求解φ(1)到φ(n)的方法,包括平方根下界复杂度的求法和线性筛法,并通过引理证明解释了线性筛法中如何更新欧拉函数值。最后,给出了C++代码实现。

Label

欧拉函数(此处将此题作为欧拉函数模板套路题分析)

Description

https://www.luogu.com.cn/problem/P2158

Solution

本题思路

我们首先转化题意:假设当前C君站在(0,0)(0,0)(0,0)处,右上角坐标为(n−1,n−1)(n-1,n-1)(n1,n1),那么:设一名站在坐标(x,y)(x,y)(x,y)处的学生:

​ 若该学生不能被看见,当且仅当∃d∈N(d∣x∧d∣y)\exist d\in N(d|x\land d|y)dN(dxdy)

进一步转化条件:如果该学生能被看见,则说明┐∃d∈N(d∣x∧d∣y)\urcorner\exist d\in N(d|x\land d|y)dN(dxdy),那么***从质因子分解的角度考虑***,此时x,yx,yx,y不存在相同的质因子,进而说明x,yx,yx,y互质。

所以,站在坐标(x,y)(x,y)(x,y)处的学生能被看见等价于gcd(x,y)=1gcd(x,y)=1gcd(x,y)=1x,yx,yx,y互质)

考虑欧拉函数的定义:φ(n)=∑i=1n[gcd(i,n)==1]\varphi(n)=\sum_{i=1}^{n}[gcd(i,n)==1]φ(n)=i=1n[gcd(i,n)==1],即:φ(n)\varphi(n)φ(n)表示[1,n][1,n][1,n]内与nnn互质的数的个数。

那么,对于此题,答案即为3+2∑i=2nφ(i)3+2\sum_{i=2}^{n}\varphi(i)3+2i=2nφ(i)。(1、考虑(x,y),(y,x)(x,y),(y,x)(x,y),(y,x)同时合法/不合法;2、(0,1),(1,0),(1,1)(0,1),(1,0),(1,1)(0,1),(1,0),(1,1)处的学生一定可以被看见,(0,x),(x,0)(x>1)(0,x),(x,0)(x>1)(0,x),(x,0)(x>1)的学生一定不能被看见)。

总结:涉及到gcd(x,y)gcd(x,y)gcd(x,y)取值可能为1的问题,往往需要用到欧拉函数。

φ(1)∼φ(n)\varphi(1)\sim\varphi(n)φ(1)φ(n)的方法
O(nn)O(n\sqrt n)O(nn)求法

由于φ(n)=n∏pp∣np−1p\varphi(n)=n\prod_{p}^{p|n}\frac{p-1}{p}φ(n)=nppnpp1,故我们可以对1∼n1\sim n1n内的每个数进行质因子分解即可。

int Phi(int x)//求phi(x)一般用利用容斥原理推出的公式,O(sqrt(n)) 
{
	ri phix=x;
	for(ri i=2;i*i<=x;++i)
		if(x%i==0)
		{
			phix=phix/i*(i-1);
			while(x%i==0)	x/=i;//由于i|x,故不会出现精度问题
		}
	if(x>1)	phix=phix/x*(x-1);//注意可能大于sqrt(x)的质因子
	return phix;
}
O(n)O(n)O(n)求法

一般的O(n)O(n)O(n)做法利用了线性筛(欧拉筛)法的良好性质。

进行筛法的过程中,对于素数nnn,直接令φ(n)=n−1\varphi(n)=n-1φ(n)=n1即可。关键在于怎么把非素数的欧拉函数表示出来。

由于线性筛具有“每一个数只会被其最小的质因子筛去”的优秀性质,故我们可以考虑合数n=p×kn=p\times kn=p×k在被它的最小质因子ppp筛去时,利用φ(p)\varphi(p)φ(p)φ(k)\varphi(k)φ(k)的值来求φ(n)\varphi(n)φ(n)(此处线性筛外层循环枚举待筛数的最大因子的筛取性质证得:若kkk为合数,当线性筛外层循环循环至kkk时,kkk是否为素数及φ(k)\varphi(k)φ(k)已被求出)。

1、p∣kp|kpk

此时说明nnn只含一个值为ppp的素因子(不是只含一个素因子),由于欧拉函数满足积性函数的性质,故当gcd(k,p)=1gcd(k,p)=1gcd(k,p)=1时,φ(n)=φ(pk)=φ(p)φ(k)=(p−1)k\varphi(n)=\varphi(pk)=\varphi(p)\varphi(k)=(p-1)kφ(n)=φ(pk)=φ(p)φ(k)=(p1)k

2、p∤kp\nmid kpk

此时p∣gcd(k,p)p|gcd(k,p)pgcd(k,p)φ(n)≠φ(pk)=φ(p)φ(k)\varphi(n)\neq\varphi(pk)=\varphi(p)\varphi(k)φ(n)=φ(pk)=φ(p)φ(k)

为了推得正确的公式,我们先证明几个引理:

引理1:设ppp为质数,则φ(pk)=pk−pk−1\varphi(p^{k})=p^k-p^{k-1}φ(pk)=pkpk1

证明:因为pkp^{k}pk只含ppp一个质因子,故[1,pk][1,p^k][1,pk]内所有与ppp不互质的数的集合可表示成{x∣xp,1≤x≤pk−1,x∈N}\{x|xp,1\leq x\leq p^{k-1},x\in N\}{xxp,1xpk1,xN}。这个集合的元素个数为pk−1p^{k-1}pk1个,那么[1,pk][1,p^k][1,pk]内与pkp^kpk互质的元素个数即为pk−pk−1p^k-p^{k-1}pkpk1,即φ(pk)=pk−pk−1\varphi(p^{k})=p^k-p^{k-1}φ(pk)=pkpk1

引理2:设ppp为质数,则φ(pk+1)=p×φ(pk)\varphi(p^{k+1})=p\times\varphi(p^k)φ(pk+1)=p×φ(pk)

证明:由引理1,得:

φ(pk+1)=pk+1−pk=p(pk−pk−1)=p×φ(pk)\varphi(p^{k+1})=p^{k+1}-p^{k}=p(p^k-p^{k-1})=p\times\varphi(p^k)φ(pk+1)=pk+1pk=p(pkpk1)=p×φ(pk)

由以上两个引理及积性函数性质,可推得:

n=p×kn=p\times kn=p×kppp为素数且p∣kp|kpk,则有:φ(n)=p×φ(k)\varphi(n)=p\times \varphi(k)φ(n)=p×φ(k)

证明:设nnn不含因子ppp的最大因子为mmm,则:

φ(n)=φ(p×k)=φ(pt×m)=φ(pt)φ(m)=pφ(pt−1)φ(m)=pφ(pt−1m)=pφ(k)\varphi(n)=\varphi(p\times k)=\varphi(p^{t}\times m)=\varphi(p^t)\varphi(m)=p\varphi(p^{t-1})\varphi(m)=p\varphi(p^{t-1}m)=p\varphi(k)φ(n)=φ(p×k)=φ(pt×m)=φ(pt)φ(m)=pφ(pt1)φ(m)=pφ(pt1m)=pφ(k)

其中t≥2,t∈Nt\geq2,t\in Nt2,tN

所以,对于∀n∈N+∀p(p∣n)\forall n\in N^{+}\forall p(p|n)nN+p(pn),有:

(1) φ(n)=φ(p)φ(np)=(p−1)φ(np),p2∤n\varphi(n)=\varphi(p)\varphi(\frac{n}{p})=(p-1)\varphi(\frac{n}{p}),p^2\nmid nφ(n)=φ(p)φ(pn)=(p1)φ(pn),p2n

(2) φ(n)=pφ(np),p2∣n\varphi(n)=p\varphi(\frac{n}{p}),p^2|nφ(n)=pφ(pn),p2n

所以,在线性筛的第二层循环时,每利用一个primeprimeprime筛去某个数时,直接利用上述公式将被筛数的φ\varphiφ值求出即可。

以上便是求φ(1)∼φ(n)\varphi(1)\sim\varphi(n)φ(1)φ(n)O(n)O(n)O(n)方法

Code

#include<cstdio>
#include<iostream>
#define ri register int
using namespace std;

const int MAXN=4e4+20;
int N,prime[MAXN>>2],phi[MAXN],cnt,ans=3;
bool isprime[MAXN];

void Phi()//O(n)求1~N的欧拉函数 
{
	isprime[1]=true; phi[1]=1;
	for(ri i=2;i<=N;++i)
	{
		if(!isprime[i])
		{
			prime[++cnt]=i;
			phi[i]=i-1;	
		}
		for(ri j=1;j<=cnt&&i*prime[j]<=N;++j)
		{
			isprime[i*prime[j]]=true;
			if(i%prime[j]==0)	phi[i*prime[j]]=phi[i]*prime[j];
			else	phi[i*prime[j]]=phi[i]*phi[prime[j]];
			if(i%prime[j]==0)	break;//这句话不能提前,否则无法处理phi[i*i](i均为质数) 
		}
	}
}

int main()
{
	scanf("%d",&N);
	Phi();
	if(N==1) { cout<<"0"; return 0; }
	for(ri i=2;i<=N-1;++i)
		ans+=phi[i]<<1;
	cout<<ans;
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值