【初等数论】欧拉函数

欧拉函数

欧拉函数的定义

欧拉函数 φ ( n ) \varphi(n) φ(n) :对于一个正整数 n n n ,小于 n n n 且与 n n n 互质的正整数的个数。

欧拉函数的积性证明

笛卡尔乘积是指在数学中,两个集合 X X X Y Y Y 的笛卡尔积(Cartesian product),又称直积,表示为 X × Y X × Y X×Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员,例如 { 1 , 2 } × { a , b } = { ( 1 , a ) , ( 1 , b ) , ( 2 , a ) , ( 2 , b ) } \{1,2\}\times \{a,b\}=\{(1,a),(1,b),(2,a),(2,b)\} {1,2}×{a,b}={(1,a),(1,b),(2,a),(2,b)}.

简化剩余系也称既约剩余系或缩系,是 m m m 的完全剩余系中与 m m m 互素的数构成的子集,如果模m的一个剩余类里所有数都与 m m m 互素,就把它叫做与模 m m m 互素的剩余类。

引理: ( a , x ) = 1 (a,x)=1 (a,x)=1 ( b , x ) = 1 (b,x)=1 (b,x)=1 ⟺ ⟺ ( a b , x ) = 1 (ab,x)=1 (ab,x)=1 ;

证明:
A A A 为模 a a a 的既约剩余系, B B B 为模 b b b 的既约剩余系, C C C 为模 a b ab ab 的既约剩余系,

定义映射 f f f : C → A × B C→A×B CA×B
f ( z ) = ( z   m o d   a , z   m o d   b ) f(z)=(z\space mod\space a,z\space mod\space b) f(z)=(z mod a,z mod b)

因为 gcd ⁡ ( a , b ) = 1 \gcd(a,b)=1 gcd(a,b)=1,由中国剩余定理可知,对于任意的 ( x , y ) ∈ A × B (x,y)∈A×B (x,y)A×B,存在唯一的 z ∈ C z∈C zC 使得:
z ≡ x   ( m o d   a ) ,   z ≡ y   ( m o d   b ) z≡x\space(mod\space a),\space z≡y\space(mod\space b) zx (mod a), zy (mod b)

这表明 f f f 是双射。

因为 ∣ C ∣ = φ ( a b ) |C|=\varphi(ab) C=φ(ab) ∣ A × B ∣ = φ ( a ) ⋅ φ ( b ) ∣A×B∣=\varphi(a)⋅\varphi(b) A×B∣=φ(a)φ(b) f f f 为双射;

所以 φ ( a b ) = φ ( a ) ⋅ φ ( b ) \varphi(ab)=\varphi(a)⋅\varphi(b) φ(ab)=φ(a)φ(b)

欧拉函数的性质

性质1:积性函数, a a a b b b 互质,则
φ ( a b ) = φ ( a ) φ ( b ) \varphi(ab)=\varphi(a)\varphi(b) φ(ab)=φ(a)φ(b)

性质2:若 p p p 为素数,则
φ ( p ) = p − 1 \varphi(p)=p−1 φ(p)=p1

性质3:若 p p p 为素数, k k k 为正整数,则
φ ( p k ) = p k − p k − 1 = p k − 1 ( p − 1 ) \varphi(p^{k})=p^{k}−p^{k-1}=p^{k-1}(p−1) φ(pk)=pkpk1=pk1(p1)

简单证明一下:因为 p p p 为素数,所以只有当一个数 q q q 的因数包含 p p p 时, q q q p p p 不互质,所以在小于 p k p^{k} pk 的数中,只有 { p , 2 p , 3 p ⋯ p k − 1 p } \{p,2p,3p\cdots p^{k-1}p\} {p,2p,3ppk1p} p p p 不互质,一共 p k − 1 p^{k-1} pk1 个,所以与 p k p^{k} pk 互质的有 p k − p k − 1 p^{k}-p^{k-1} pkpk1

性质4:质因数分解形式的公式
φ ( n ) = n ∏ i = 1 c ( 1 − 1 p i ) \varphi(n)=n\prod_{i=1}^{c}(1- \frac{1}{p_{i}}) φ(n)=ni=1c(1pi1)

证明: φ ( n ) = φ ( p 1 k 1 ) ⋅ φ ( p 2 k 2 ) ⋯ φ ( p c k c ) \varphi(n)=\varphi(p_{1}^{k_{1}})\cdot\varphi(p_{2}^{k_{2}})\cdots\varphi(p_{c}^{k_{c}}) φ(n)=φ(p1k1)φ(p2k2)φ(pckc)

   ⟹    φ ( n ) = ( p 1 k 1 − p 1 k 1 − 1 ) ⋅ ( p 2 k 2 − p 2 k 2 − 1 ) ⋯ ( p c k c − p c k c − 1 ) \implies\varphi(n)=(p_{1}^{k_{1}}-p_{1}^{k_{1}-1})\cdot(p_{2}^{k_{2}}-p_{2}^{k_{2}-1})\cdots(p_{c}^{k_{c}}-p_{c}^{k_{c}-1}) φ(n)=(p1k1p1k11)(p2k2p2k21)(pckcpckc1)

   ⟹    φ ( n ) = p 1 k 1 ( 1 − 1 p 1 ) ⋅ p 2 k 2 ( 1 − 1 p 2 ) ⋯ p c k c ( 1 − 1 p c ) \implies\varphi(n)=p_{1}^{k_{1}}(1- \frac{1}{p_{1}})\cdot p_{2}^{k_{2}}(1-\frac{1}{p_{2}})\cdots p_{c}^{k_{c}}(1- \frac{1}{p_{c}}) φ(n)=p1k1(1p11)p2k2(1p21)pckc(1pc1)

   ⟹    φ ( n ) = n ( 1 − 1 p 1 ) ⋅ ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p c ) \implies\varphi(n)=n(1- \frac{1}{p_{1}})\cdot (1-\frac{1}{p_{2}})\cdots (1- \frac{1}{p_{c}}) φ(n)=n(1p11)(1p21)(1pc1)

   ⟹    φ ( n ) = n ∏ i = 1 c ( 1 − 1 p i ) \implies\varphi(n)=n\prod_{i=1}^{c}(1- \frac{1}{p_{i}}) φ(n)=ni=1c(1pi1)

性质5:一个重要的恒等式
∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi(d)=n dnφ(d)=n

证明:设集合 S = { 1 , 2 , 3 , ⋯   , n } S=\{1,2,3,\cdots,n\} S={1,2,3,,n},

对于每一个因子 d   ∣   n d\space|\space n d  n,定义子集 S d = { k ∈ S   ∣   gcd ⁡ ( k , n ) = d } S_{d}=\{k\in S \space |\space \gcd(k,n)=d\} Sd={kS  gcd(k,n)=d}

也就是说 S d S_{d} Sd S S S 中与 n n n 的最大公约数为 d d d 的数的集合。

根据 S d S_{d} Sd 集合定义,可知 k = d ⋅ m   ( 1 ≤ m ≤ n d ) k=d\cdot m \space (1\le m\le \frac{n}{d}) k=dm (1mdn)

由于 gcd ⁡ ( k , n ) = d \gcd(k,n)=d gcd(k,n)=d,可推出 gcd ⁡ ( m , n d ) = 1 \gcd(m,\frac{n}{d})=1 gcd(m,dn)=1,且满足该式的 m m m φ ( n d ) \varphi(\frac{n}{d}) φ(dn) 个,

所以 ∣ S d ∣ = φ ( n d ) |S_{d}|=\varphi(\frac{n}{d}) Sd=φ(dn)

由定义可得, S S S 是所有 S d S_{d} Sd 的并集,所有的 S d S_{d} Sd 都不相交,即
S = ⋃ d ∣ n S d , S d 1 ∩ S d 2 = ∅ ( d 1 ≠ d 2 ) S=\bigcup_{d|n}S_{d},S_{d_{1}}\cap S_{d_{2}}=\varnothing (d_{1}\not =d_{2}) S=dnSdSd1Sd2=(d1=d2)

因此
n = ∣ S ∣ = ∑ d ∣ n ∣ S d ∣ = ∑ d ∣ n φ ( n d ) = ∑ d ∣ n φ ( d ) n=|S|=\sum_{d|n}|S_{d}|=\sum_{d|n}\varphi(\frac{n}{d})=\sum_{d|n}\varphi(d) n=S=dnSd=dnφ(dn)=dnφ(d)

欧拉函数的求法

单个数的欧拉函数值

由于只需要单个数,可以直接借助质因数分解后的公式(上文的性质4)直接计算,时间复杂度 O ( n ) O(\sqrt{n}) O(n ),代码如下:

ll phi(ll x){ //typedef long long ll;
    ll res=x;
    for(ll i=2;i*i<=x;i++)//由于大于sqrt(n)的质因数最多只有一个,所以只需要枚举到sqrt(n),再特判即可
        if(x%i==0){ //如果是质因数
            res=res/i*(i-1);//先除后乘,防止爆long long
            while(x%i==0) x/=i;//质因数分解
        }
    if(x!=1) res=res/x*(x-1);//若x最后的值不为1,证明存在比sqrt(n)大的质因数
    return res;
}

埃氏筛打表求值

根据埃氏筛的性质,我们可以利用它,逐步筛去质因子的贡献,直接得到每个数的 φ ( n ) \varphi(n) φ(n),时间复杂度与埃氏筛求素数一致,均为 O ( n   log ⁡   log ⁡   n ) O(n\space \log\space \log\space n) O(n log log n),代码如下:

void eratos(){
	for(int i=2;i<maxx;i++){ //maxx是预处理的最大上限
		if(E[i]) continue;//如果E[i]有值,证明它不是素数
		for(int j=i;j<maxx;j+=i){ //筛去质数i的倍数j
			if(!E[j]) E[j]=j;//赋成它自身的值
			E[j]=E[j]/i*(i-1);//公式计算
		}
	}
	return ;
}

欧拉筛打表求值

埃氏筛可降低时间复杂度,欧拉筛当然也可以,我们可以用欧拉函数的积性对欧拉筛进行改造,时间复杂度与欧拉筛求素数一致,均为 O ( n ) O(n) O(n),代码如下:

void oula(){
	phi[1]=1; //初始化phi[1]
	for(int i=2;i<=n;i++){
		if(!st[i])//st[i]储存i是否被筛过,!st[i]说明i为素数
			phi[i]=i-1,pri[++cnt]=i;//pri[i]是欧拉筛的素数集合
		for(int j=1;j<=cnt;j++){
			int x=i*pri[j];
			if(x>n) break;
			st[x]=1;
			if(i%pri[j]==0){ //判断pri[j]与i是否互质
				phi[x]=phi[i]*pri[j];//不互质时的计算方式(后面有证明)
				break;//欧拉筛保证每一个合数只被筛一次的核心
			}
			phi[x]=phi[i]*(pri[j]-1);//pri[j]与i互质,直接利用积性
		}
	}
    return ;
}

证明: φ ( n ) = φ ( p 1 k 1 ) ⋅ φ ( p 2 k 2 ) ⋯ φ ( p i k i ) ⋯ φ ( p c k c ) \varphi(n)=\varphi(p_{1}^{k_{1}})\cdot\varphi(p_{2}^{k_{2}})\cdots\varphi(p_{i}^{ki})\cdots\varphi(p_{c}^{k_{c}}) φ(n)=φ(p1k1)φ(p2k2)φ(piki)φ(pckc)

   ⟹    φ ( p i ⋅ n ) = φ ( p 1 k 1 ) ⋅ φ ( p 2 k 2 ) ⋯ φ ( p i k i + 1 ) ⋯ φ ( p c k c ) \implies\varphi(p_{i}\cdot n)=\varphi(p_{1}^{k_{1}})\cdot\varphi(p_{2}^{k_{2}})\cdots\varphi(p_{i}^{ki+1})\cdots\varphi(p_{c}^{k_{c}}) φ(pin)=φ(p1k1)φ(p2k2)φ(piki+1)φ(pckc)

   ⟹    φ ( p i ⋅ n ) = ( p 1 k 1 − p 1 k 1 − 1 ) ⋅ ( p 2 k 2 − p 2 k 2 − 1 ) ⋯ ( p i k i + 1 − p i k i ) ⋯ ( p c k c − p c k c − 1 ) \implies\varphi(p_{i}\cdot n)=(p_{1}^{k_{1}}-p_{1}^{k_{1}-1})\cdot(p_{2}^{k_{2}}-p_{2}^{k_{2}-1})\cdots(p_{i}^{k_{i+1}}-p_{i}^{k_{i}})\cdots(p_{c}^{k_{c}}-p_{c}^{k_{c}-1}) φ(pin)=(p1k1p1k11)(p2k2p2k21)(piki+1piki)(pckcpckc1)

   ⟹    φ ( p i ⋅ n ) = p 1 k 1 ( 1 − 1 p 1 ) ⋅ p 2 k 2 ( 1 − 1 p 2 ) ⋯ p i k i + 1 ( 1 − 1 p i ) ⋯ p c k c ( 1 − 1 p c ) \implies\varphi(p_{i}\cdot n)=p_{1}^{k_{1}}(1- \frac{1}{p_{1}})\cdot p_{2}^{k_{2}}(1-\frac{1}{p_{2}})\cdots p_{i}^{k_{i+1}}(1- \frac{1}{p_{i}})\cdots p_{c}^{k_{c}}(1- \frac{1}{p_{c}}) φ(pin)=p1k1(1p11)p2k2(1p21)piki+1(1pi1)pckc(1pc1)

   ⟹    φ ( p i ⋅ n ) = p i ⋅ n ( 1 − 1 p 1 ) ⋅ ( 1 − 1 p 2 ) ⋯ ( 1 − 1 p i ) ⋯ ( 1 − 1 p c ) \implies\varphi(p_{i}\cdot n)=p_{i}\cdot n(1- \frac{1}{p_{1}})\cdot (1-\frac{1}{p_{2}})\cdots (1- \frac{1}{p_{i}})\cdots (1- \frac{1}{p_{c}}) φ(pin)=pin(1p11)(1p21)(1pi1)(1pc1)

即: φ ( p i ⋅ n ) = p i ⋅ n ∏ i = 1 c ( 1 − 1 p i ) \varphi(p_{i}\cdot n)=p_{i}\cdot n\prod_{i=1}^{c}(1- \frac{1}{p_{i}}) φ(pin)=pini=1c(1pi1)

练习题

洛谷-P2023 Longge 的问题

P2303 [SDOI2012] Longge 的问题

题目背景
Longge 的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。
题目描述
现在问题来了:给定一个整数 n n n,你需要求出 ∑ i = 1 n gcd ⁡ ( i , n ) \sum\limits_{i=1}^n \gcd(i, n) i=1ngcd(i,n),其中 gcd ⁡ ( i , n ) \gcd(i, n) gcd(i,n) 表示 i i i n n n 的最大公因数。
输入格式
输入只有一行一个整数,表示 n n n
输出格式
输出一行一个整数表示答案。
对于 60 % 60\% 60% 的数据,保证 n ≤ 2 16 n\leq 2^{16} n216
对于 100 % 100\% 100% 的数据,保证 1 ≤ n < 2 32 1\leq n< 2^{32} 1n<232

Solution: 由题意可知 gcd ⁡ ( i , n ) \gcd(i,n) gcd(i,n) 一定为 n n n 的一个因数,我们不妨将问题转化为,求对于每一个 d ∣ n d|n dn,从1到 n n n 有多少个数满足 gcd ⁡ ( i , n ) = d \gcd(i,n)=d gcd(i,n)=d ,只需将每一个 d d d 乘上相应的次数求和即可;

可能满足上面等式的数一定有 i ∈ { d , 2 d , 3 d , ⋯   , d ⋅ n d } i\in\{d,2d,3d,\cdots,d\cdot \frac{n}{d}\} i{d,2d,3d,,ddn},我们令 i = k ⋅ d   ( 1 ≤ k ≤ n d ) i=k\cdot d\space(1\leq k\leq \frac{n}{d}) i=kd (1kdn)

又因为 n = d ⋅ n d n=d\cdot\frac{n}{d} n=ddn,所以只有当 k k k n d \frac{n}{d} dn 互质的时候, n n n i i i 不存在更大的公因数,问题又转化成为求所有的 d ⋅ φ ( n d ) d\cdot\varphi(\frac{n}{d}) dφ(dn) 之和

∑ i = 1 n gcd ⁡ ( i , n ) = ∑ d ∣ n d ⋅ ∑ i = 1 n [ gcd ⁡ ( i , n ) = d ] = ∑ d ∣ n d ⋅ φ ( n d ) \sum\limits_{i=1}^n \gcd(i, n)=\sum_{d|n}d\cdot\sum_{i=1}^{n}[\gcd(i,n)=d]=\sum_{d|n}d\cdot\varphi(\frac{n}{d}) i=1ngcd(i,n)=dndi=1n[gcd(i,n)=d]=dndφ(dn)

由于 2 32 2^{32} 232 以内数的因数很少,所以可以直接求单个数的欧拉函数值,代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace zyx_{

ll n,ans;
ll phi(ll x){ //求取单个数的欧拉函数值
    ll res=x;
    for(ll i=2;i*i<=x;i++)
        if(x%i==0){
            res=res/i*(i-1);
            while(x%i==0) x/=i;
        }
    if(x!=1) res=res/x*(x-1); //别忘记大于sqrt(x)的质因数
    return res;
}
int my_main(){
	cin>>n;
	for(ll i=1;i*i<=n;i++)
		if(n%i==0){
			ans+=i*phi(n/i);
			if(i*i!=n) ans+=(n/i)*phi(i);
		}
	cout<<ans;
	return 0;
}

}
int main(){
	zyx_::my_main();
	return 0;
}

洛谷-P2158 仪仗队

P2158 [SDOI2008] 仪仗队

题目描述
作为体育委员,C 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N × N N \times N N×N 的方阵,为了保证队伍在行进中整齐划一,C 君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C 君希望你告诉他队伍整齐时能看到的学生人数。

输入格式
一行,一个正整数 N N N
输出格式
输出一行一个数,即 C 君应看到的学生人数。
说明/提示
对于 100 % 100 \% 100% 的数据, 1 ≤ N ≤ 40000 1 \le N \le 40000 1N40000

Solution: 我可以建立平面直角坐标系,不难发现,当某同学的坐标 ( x , y ) (x,y) (x,y) 不互质时,其与 C 君 ( 0 , 0 ) (0,0) (0,0) 之间的连线上,必定存在更小的正整数对 ( x , , y , ) (x^{,},y^{,}) (x,,y,),挡住了 C 君的视线,使得 ( x , y ) (x,y) (x,y) 的同学不能被看到,换句话说,该问题转化为求所有满足 x , y x,y x,y 互质的点对的个数,

我们不妨逐层累加点的个数,观察发现,对角线两侧的点对称分布,所以只需将每列的 φ ( i ) \varphi(i) φ(i) 乘以2求和即可,当然,不要忘记了对角线上还有一个同学!

#include<bits/stdc++.h>
using namespace std;
const int N=4e4+10;
namespace zyx_{

int n,sum=1,cnt,pri[N],phi[N];
bool st[N];
void oula(){ //欧拉筛打表欧拉函数
    phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!st[i]) pri[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt;j++){
			int x=pri[j]*i;
			if(x>n) break;
			st[x]=true;
			if(i%pri[j]==0){
                phi[x]=phi[i]*pri[j];
                break;
            }
			phi[x]=phi[i]*phi[pri[j]];
		}
	}
}
int my_main(){
	cin>>n;
	if(n==1){ //注意需要特判
		cout<<0;
		return 0;
	}
	oula();
	for(int i=2;i<=n;i++){
		sum+=phi[i-1]*2;
	}
	cout<<sum;
	return 0;
}

}
int main(){
	zyx_::my_main();
	return 0;
}

洛谷-P2568 GCD

P2568 GCD

题目描述
给定正整数 n n n,求 1 ≤ x , y ≤ n 1\le x,y\le n 1x,yn gcd ⁡ ( x , y ) \gcd(x,y) gcd(x,y) 为素数的数对 ( x , y ) (x,y) (x,y) 有多少对。
输入格式
只有一行一个整数,代表 n n n
输出格式
一行一个整数表示答案。
说明/提示
样例输入输出 1 解释
对于样例,满足条件的 ( x , y ) (x,y) (x,y) ( 2 , 2 ) (2,2) (2,2) ( 2 , 4 ) (2,4) (2,4) ( 3 , 3 ) (3,3) (3,3) ( 4 , 2 ) (4,2) (4,2)
数据规模与约定
对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 10 7 1\le n\le10^7 1n107
来源:bzoj2818

Solution: 我们可以设 n n n 以内的素数集合为 P P P ,则 gcd ⁡ ( x , y ) = d   ( d ∈ P ) \gcd(x,y)=d\space(d\in P) gcd(x,y)=d (dP),根据最大公约数的定义,可以得到 x , y x,y x,y 均为 d d d 的倍数,即 x , y ∈ { d , 2 d , 3 d , ⋯   , d ⋅ n d } x,y\in\{d,2d,3d,\cdots,d\cdot\frac{n}{d}\} x,y{d,2d,3d,,ddn},不妨设 x = n ⋅ d , y = m ⋅ d   ( 1 ≤ x , y ≤ n d ) x=n\cdot d,y=m\cdot d\space(1\leq x,y\leq \frac{n}{d}) x=ndy=md (1x,ydn),因为 d d d 为素数,所以 gcd ⁡ ( n , m ) = 1 \gcd(n,m)=1 gcd(n,m)=1

该问题可以转化为,对于每一个 n n n 以内的素数 d d d n d \frac{n}{d} dn 范围内有多少种 ( n , m ) (n,m) (n,m) 的组合,使得 gcd ⁡ ( n , m ) = 1 \gcd(n,m)=1 gcd(n,m)=1,求它们的加和,

由于 n , m n,m n,m 地位对等,我们可以固定住 n n n,来看 m m m,根据欧拉函数的定义,所有组合的个数即为1到 n d \frac{n}{d} dn 的所有 φ ( i ) \varphi(i) φ(i),只需在欧拉筛中加入前缀和即可,对于 m m m 也同理,但是由于 ( 1 , 1 ) (1,1) (1,1) 的存在,最后结果应乘以2再减去1;

a n s = ∑ d ∈ P { 2 [ ∑ i = 1 n d φ ( i ) ] − 1 } ans=\sum_{d\in P}\{2[\sum_{i=1}^{\frac{n}{d}}\varphi(i)]-1\} ans=dP{2[i=1dnφ(i)]1}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+10;
namespace zyx_{

ll read(){ //快读快写
	ll x=0;int f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
void print(ll x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) print(x/10);
	putchar(x%10+'0');
	return ;
}
ll n,ans,cnt,pri[N];
ll phi[N],sumphi[N];
bool st[N];
void oula(){ //欧拉筛打表欧拉函数
    sumphi[1]=phi[1]=1;
	for(int i=2;i<=n;i++){
		if(!st[i]) phi[i]=i-1,pri[++cnt]=i;
        sumphi[i]=sumphi[i-1]+phi[i]; //直接计算前缀和
		for(int j=1;j<=cnt;j++){
			int x=i*pri[j];
			if(x>n) break;
			st[x]=1;
			if(i%pri[j]==0){
				phi[x]=phi[i]*pri[j];
				break;
			}
			phi[x]=phi[i]*(pri[j]-1);
		}
	}
    return ;
}
int my_main(){
	n=read();
    oula();
    for(int i=1;i<=cnt;i++)
        ans+=sumphi[n/pri[i]]*2-1;
	print(ans);
	return 0;
}

}
int main(){
	zyx_::my_main();
	return 0;
}

洛谷-P3601 签到题

P3601 签到题

题目背景
这是一道签到题!
建议做题之前仔细阅读数据范围!
题目描述
我们定义一个函数: qiandao ⁡ ( x ) \operatorname{qiandao}(x) qiandao(x) 为小于等于 x x x 的数中,与 x x x 不互质的数的个数。
这题作为签到题,给出 l l l r r r,求出:
∑ i = l r qiandao ⁡ ( i )   m o d   666623333 \sum_{i=l}^r \operatorname{qiandao}(i)\bmod 666623333 i=lrqiandao(i)mod666623333
输入格式
一行两个整数, l l l r r r
输出格式
一行一个整数表示答案。
输入输出样例 #1
输入 #1
233 2333
输出 #1
1056499
输入输出样例 #2
输入 #2
2333333333 2333666666
输出 #2
153096296
说明/提示
对于 30 % 30\% 30% 的数据, l , r ≤ 10 3 l,r\leq 10^3 l,r103
对于 60 % 60\% 60% 的数据, l , r ≤ 10 7 l,r\leq 10^7 l,r107
对于 100 % 100\% 100% 的数据, 1 ≤ l ≤ r ≤ 10 12 1 \leq l \leq r \leq 10^{12} 1lr1012 r − l ≤ 10 6 r-l \leq 10^6 rl106

Solution: 虽然 1 ≤ l ≤ r ≤ 10 12 1 \leq l \leq r \leq 10^{12} 1lr1012 的数据范围过大,但由于 r − l ≤ 10 6 r-l \leq 10^6 rl106 ,我们可以考虑,将区间缩减到 [ 1 , 10 6 ] [ 1,10^{6}] [1,106] ,毕竟大于 n \sqrt{n} n 的质因数最多只有一个,可以先用欧拉筛找出 10 6 10^{6} 106 以内的所有素数,接着统计各个质数对区间 [ l , . r ] [l,.r] [l,.r] 的贡献即可,具体详解请看代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=666623333;//模数
const int N=1e6+10;
namespace zyx_{

ll read(){ //快速读取
	ll x=0;int f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
void print(ll x){ //快速输出
	if(x<0) print('-'),x=-x;
	if(x>9) print(x/10);
	putchar(x%10+'0');
	return ;
}
ll l,r,pri[N],phi[N],val[N];
bool st[N];
ll cnt,ans;
void oula(){ //欧拉筛筛素数
	for(int i=2;i<=N;i++){
		if(!st[i]) pri[++cnt]=i;
		for(int j=1;j<=cnt&&pri[j]*i<=N;j++){
			st[pri[j]*i]=true;
			if(i%pri[j]==0) break;
		}
	}
	return ;
}
int my_main(){
	l=read(); r=read(); oula();
    for(ll i=l;i<=r;i++){
    	phi[i-l]=val[i-l]=i; //初始化欧拉函数值与自身数值
    }
    for(ll i=1;i<=cnt&&pri[i]*pri[i]<=r;i++){
    	ll x=l/pri[i]*pri[i]+pri[i];//找到区间中质数pri[i]的最小的倍数
    	if(l%pri[i]==0) x=l;//特判
    	for(ll j=x;j<=r;j+=pri[i]){
    		phi[j-l]=phi[j-l]/pri[i]*(pri[i]-1);//欧拉函数公式
    		while(val[j-l]%pri[i]==0) val[j-l]/=pri[i];//质因数分解
    	}
    }
    for(ll i=l;i<=r;i++){
    	if(val[i-l]!=1) phi[i-l]=phi[i-l]/val[i-l]*(val[i-l]-1);//特殊处理存在大于sqrt(n)的质因数时的情况
    	(ans+=(i-phi[i-l])%mod)%=mod;//一定不要忘记了取模
    }
    print(ans);
	return 0;
}

}
int main(){
	zyx_::my_main();
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值