[ACM]【欧拉函数】POJ 2478 Farey Sequence

Farey Sequence

传送门
题意:
题意
题目

写在前面

继续补1月份的题,才发现这道题这么简单,果然当时的我太菜了。(当然现在的我也很菜…。)

思路

看到0<a<b<=n(gcd(a,b)==1)0<a<b<=n(gcd(a,b)==1),我们仔细观察,会发现,答案就是欧拉函数的前缀和。为什么呢?发现F4比起F3,不就是多出来了,有关于4的,从1到4数的,gcd=1的个数吗?再看看欧拉函数的定义,小于等于n与n互质的个数。

求欧拉函数的前缀和,我会的有三种方法
(1)线性筛出欧拉函数,老老实实O(n)求前缀和(这可能也是这道题的标准作法,因为这道题就是道水题)。
(2)杜教筛
(3)通过莫比乌斯反演来求,要借助莫比乌斯函数,所以已经求出了莫比乌斯函数前缀和时这样做最快。时间复杂度O(n23)O(n^{\frac{2}{3}})

线性筛

首先我们回忆一下线性筛模板:
原理:每个合数都被其最小质因子筛去。

void init(){
	for(int i=2;i<maxn;i++){
		if(!vis[i]) pri[cnt++]=i;
		for(int j=0;j<cnt&&1ll*i*pri[j]<maxn;j++){
			vis[i*pri[j]]=1;
			//break是因为这个i被pri[j]与之前的某个i筛过了
			//如果i再与其他质数相乘
			//得到的值早就被这个pri[j]筛过
			if(i%pri[j]==0) break;
		}
	}
}

求欧拉函数的线性筛:
原理:
直接套定义φ(n)=n×i=1spi1pi\varphi(n)=n\times \prod_{i=1}^s\frac{p_i-1}{p_i}。每个数一开始为n,后来被其因子更新。

void get_phi(int n) {
	phi[1]=1;
	for(int i=2;i<=n;i++)
		if(!phi[i])
			for(int j=i;j<=n;j+=i) {
        		if(!phi[j]) phi[j]=j;
        		phi[j]=phi[j]/i*(i-1);
      		}
}

同时求质数的线性筛:
原理:
p1p_1nn的最小质因子,n=np1n'=\frac{n}{p_1},线性筛的过程中,nnp1p_1筛掉。按照欧拉筛(线性筛)的套路,我们会面对两种情况:nmod  p10n'\mod p_1\neq0nmod  p1=0n'\mod p_1= 0

性质1
如果nmod  p10n'\mod p_1\neq0,此时nn'p1p_1互质,那么φ(n)=φ(n)×φ(p1)\varphi(n)=\varphi(n')\times \varphi(p_1)(积性函数)

性质2
如果nmod  p1=0n'\mod p_1= 0,此时nn'包含了nn的所有因子,所以φ(n)=n×i=1spi1pi\varphi(n)=n\times \prod_{i=1}^s\frac{p_i-1}{p_i}
φ(n)=p1×n×i=1spi1pi\varphi(n)=p_1\times n'\times \prod_{i=1}^s\frac{p_i-1}{p_i}
就等价于(因为注意后面的fraction不考虑质因子的幂次)
φ(n)=p1×φ(n)\varphi(n)=p_1\times \varphi(n')

void init(){
	for(int i=2;i<maxn;i++){
		if(!vis[i]){
			phi[i]=i-1;
			pri[cnt++]=i;
		}
		for(int j=0;j<cnt&&1ll*pri[j]*i<maxn;j++){
			vis[i*pri[j]]=1;
			if(i%pri[j])
				phi[i*pri[j]]=phi[i]*(pri[j]-1);//性质1 
			else {
				phi[i*pri[j]]=phi[i]*pri[j];//性质2 
				break;
			}
		}
	}
}

好了,那我们就选择定义求欧拉函数的线性筛法来做题。

代码:

#include<stdio.h>
typedef long long ll;
ll phi[1000005],sum[1000005];
void get_phi(ll n) {
	phi[1]=0;
	for(ll i=2;i<=n;i++)
		if(!phi[i])
			for(ll j=i;j<=n;j+=i) {
        		if(!phi[j]) phi[j]=j;
        		phi[j]=phi[j]/i*(i-1);
      		}
}
int main(){
	get_phi(1000000);
	for(ll i=1;i<=1000000;i++){
		sum[i]=sum[i-1]+phi[i];
	}
	ll n;
	while(~scanf("%lld",&n)&&n){
		printf("%lld\n",sum[n]);
	}
}

杜教筛

S(i)=i=1nφ(i)S(i)=\sum_{i=1}^n\varphi(i)
根据Dirichlet卷积:(fg)(n)=dnf(d)g(nd)(f\ast g)(n)=\sum_{d|n}f(d)g(\frac{n}{d})
我们有,φ1=ID\varphi\ast 1=IDIDID函数即f(x)=xf(x)=x)(证明见下)
(ATTENTION:先坑了抱歉,期末复习了)

莫比乌斯反演

知识传送门
由文字定义可知,欧拉函数就是i=1n[gcd(i,n)==1]\sum_{i=1}^n[gcd(i,n)==1],那么欧拉函数的前缀和其实就是a=1nb=1n[gcd(a,b)==1]\sum_{a=1}^n\sum_{b=1}^n[gcd(a,b)==1]。(前缀和嘛,外面多累加一次)。由莫比乌斯函数的性质,我们得到a=1nb=1ndgcd(a,b)μ(d)\sum_{a=1}^n\sum_{b=1}^n\sum_{d|gcd(a,b)}\mu(d)
我们稍作变换,得到d=1nμ(d)nd2\sum_{d=1}^n\mu(d)\lfloor\frac{n}{d}\rfloor^2

涉及知识

欧拉函数

定义

性质

φ1=ID\varphi\ast 1=ID

单个求值(定义)

线性筛

见上。

前缀和

见上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章