[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

單個求值(定義)

線性篩

見上。

前綴和

見上。

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