【数论】欧拉函数与欧拉定理

版权声明:来自达羌蒟蒻 https://blog.csdn.net/PHenning/article/details/89047432

数学杀我

欧拉函数

对于一个正整数 x x ,小于 x x 且和 x x 互质的正整数的个数,记做 φ ( x ) \varphi(x) 。其中 φ ( 1 ) \varphi(1) 被定义为 1 1
φ ( x ) = x p x p 1 p \varphi(x)=x\prod_{p|x}\frac{p-1}p
部分性质:

  • p p 是质数, φ ( p ) = p 1 \varphi(p)=p-1
  • x x 是质数 p p k k 次幂,即 x = p k x=p^k ,有 φ ( x ) = p k p k 1 = ( p 1 ) p k 1 \varphi(x)=p^k-p^{k-1}=(p-1)p^{k-1}
  • 欧拉函数是积性函数(若 x , y x,y 互质,则 φ ( x y ) = φ ( x ) φ ( y ) \varphi(xy)=\varphi(x)\varphi(y) )。

根据通式,枚举 x x 的质因数。可枚举 x \sqrt x 以内的质因数,若存在大于 x \sqrt x 的质因数则额外处理。
时间复杂度: O ( n ) O(\sqrt n)

int phi(int x){
  int ans=x;
  for(int i=2;i*i<=x;i++)if(!(x%i)){
    ans-=ans/i;
    while(!(x%i))x/=i;
  }
  if(x>1)ans-=ans/x;
  return ans;
}

欧拉筛

Eratosthenes筛法筛质数:先假设所有的数都是质数。从小到大讨论,若 i i 是质数,则 i i 的倍数全部标记为合数。
用同样的方法求欧拉函数,先设 φ ( i ) = i \varphi(i)=i ,若 i i 是质数,则 i i 的倍数(即包含 i i 这个质因数的数)的函数值都要更新。
时间复杂度: O ( n log 2 log 2 n ) O(n\log_2\log_2n)

void make_prime(bool*mk,int n){
  memset(mk,0,sizeof(mk));mk[1]=1;
  for(int i=2;i<=n;i++)if(!mk[i])
    for(int j=i+i;j<=n;j+=i)mk[j]=1;
}
void make_phi(int*phi,int n){
  for(int i=1;i<=n;i++)phi[i]=i;
  for(int i=2;i<=n;i++)if(phi[i]==i)
    for(int j=i;j<=n;j+=i)phi[j]=phi[j]/i*(i-1);
}

Euler筛法筛质数:每个合数仅被它的最小质因数筛去正好一次。
线性筛求欧拉函数利用了欧拉函数的一些性质( p p 为质数):

  • φ ( p ) = p 1 \varphi(p)=p-1
  • i m o d &ThinSpace;&ThinSpace; p = 0 i\mod p=0 ,那么 φ ( i p ) = φ ( i ) p \varphi(ip)=\varphi(i)p
  • i m o d &ThinSpace;&ThinSpace; p 0 i\mod p\neq0 ,那么 φ ( i p ) = φ ( i ) ( p 1 ) \varphi(ip)=\varphi(i)(p-1)

时间复杂度: O ( n ) O(n)

void make_prime(bool*mk,int*p,int n){
  memset(mk,0,sizeof(mk));mk[1]=1;
  for(int i=2;i<=n;i++){
    if(!mk[i])p[++tot]=i;
    for(int j=1;j<=tot&&i*p[j]<=n;j++){
      mk[i*p[j]]=1;
      if(!(i%p[j]))break;
    }
  }
}
void make_phi(int*phi,bool*mk,int*p,int n){
  memset(mk,0,sizeof(mk));mk[1]=phi[1]=1;
  for(int i=2;i<=n;i++){
    if(!mk[i])p[++tot]=i,phi[i]=i-1;
    for(int j=1;j<=tot&&i*p[j]<=n;j++){
      mk[i*p[j]]=1;
      if(i%p[j])phi[i*p[j]]=phi[i]*(p[j]-1);
      else{phi[i*p[j]]=phi[i]*p[j];break;}
    }
  }
}

GCD的个数(NKOJ 3684)

问题描述
给定两个正整数 n n , m m , 求满足下列两个条件的 x x 的个数:
条件1: 1 x n 1\leqslant x\leqslant n
条件2: g c d ( x , n ) m gcd(x,n)\geqslant m

输入格式
一行,两个整数 n n m m

输出格式
一行,一个整数,表示所求结果

样例输入
10 2

样例输出
6

提示
2 n 1000000000 , 1 m N 2\leqslant n\leqslant 1000000000,1\leqslant m\leqslant N

先考虑满足 x n x\leqslant n g c d ( x , n ) = d gcd(x,n)=d x x 的个数,显然 g c d ( x d , n d ) = 1 gcd(\frac xd,\frac nd)=1
x d \therefore\frac xd n d \lfloor\frac nd\rfloor 内的与 n d \lfloor\frac nd\rfloor 互质的数,总共有 φ ( n d ) \varphi(\lfloor\frac nd\rfloor) 个。
于是只需枚举 n n 的因数 d d ,当 d m d\geqslant m 时答案增加 φ ( n d ) \varphi(\lfloor\frac nd\rfloor) 。由于 n n 较大,可以把枚举量减少到 n \sqrt n 。特殊情况特殊处理。

typedef long long LL;
LL phi(LL x){
  LL ans=x;
  for(LL i=2;i*i<=x;i++)if(!(x%i)){
    ans=ans-ans/i;
  	while(!(x%i))x=x/i;
  }
  if(x>1)ans=ans-ans/x;
  return ans;
}
int main(){
  LL n,m,ans=0;
  read(&n,&m);
  for(LL d=1;d*d<=n;d++){
    if(d>=m&&!(n%d))ans+=phi(n/d);
    if(d*d<n&&!(n%d)&&n/d>=m)ans+=phi(d);
  }
  write(ans,"\n");
  return 0;
}

找互质(NKOJ 4494)

问题描述
给一个整数 n n ,请你在指定区间 [ a , b ] [a,b] 中找出共有多少个数是与 n n 互质的。

输入格式
一行,三个整数 a , b , n a,b,n

输出格式
一行,一个整数,表示计算结果。

样例输入
1 10 2

样例输出
5

提示
1 a b 1 0 15 1\leqslant a\leqslant b\leqslant 10^{15}
1 n 1 0 9 1\leqslant n\leqslant 10^9

求区间 [ a , b ] [a,b] 中与 n n 互质的数的个数,可以分别求 [ 1 , a 1 ] [1,a-1] [ 1 , b ] [1,b] 中与 n n 互质的数的个数。
如何求区间 [ 1 , x ] [1,x] 中与 n n 互质的数的个数?在 x x 个数中除去与 n n 有共同质因数的数,剩下的就是与 n n 互质的数。
所以先将 n n 分解质因数(求欧拉函数时会枚举质因数)。答案先设为 x x ,假设每个数都与 n n 互质;对于每一种质因数的组合 d d ,答案减去 x d \lfloor\frac xd\rfloor ,就除去了 [ 1 , x ] [1,x] d d 的倍数。枚举所有组合,根据容斥原理奇加偶减即可求出答案。

代码中用 t o t tot 位二进制表示是否选取质因数集合中的各个元素。

typedef long long LL;
LL pfact[50],tot=0,a,b,n;
void make_primefact(LL n){
  for(LL i=2;i*i<=n;i++)if(!(n%i)){
    pfact[++tot]=i;
    while(!(n%i))n/=i;
  }
  if(n>1)pfact[++tot]=n;
}
LL calc(LL x){
  LL ans=x,s=1ll<<tot;
  for(LL i=1;i<s;i++){
    LL t=i,it=1,d=1,cnt=0;
    while(t){
      if(t&1)d*=pfact[it],cnt++;
      it++,t>>=1;
    }
    ans+=x/d*((cnt&1)?-1:1);
  }
  return ans;
}
int main(){
  read(&a,&b,&n);
  make_primefact(n);
  write(a>b?0:calc(b)-calc(a-1),"\n");
  return 0;
}

费马小定理

如果 p p 是素数,且 a a p p 互质,即 g c d ( a , p ) = 1 gcd(a,p)=1 ,那么
a p 1 1 ( m o d p ) a^{p-1}\equiv1\pmod p

证明:
有小于质数 p p p 1 p-1 个数构成的集合 A = { 1 , 2 , 3 , , p 1 } A=\{1,2,3,\ldots,p-1\} ,显然 A A 中的数都与 p p 互质。
将集合 A A 中的数乘以 a a 并对 p p 取模,放入集合 B B ,于是 B = { a m o d &ThinSpace;&ThinSpace; p , 2 a m o d &ThinSpace;&ThinSpace; p , 3 a m o d &ThinSpace;&ThinSpace; p , , ( p 1 ) a m o d &ThinSpace;&ThinSpace; p } B=\{a\mod p,2a\mod p,3a\mod p,\ldots,(p-1)a\mod p\}
B B 中的数都小于 p p ,并且由于 g c d ( a , p ) = 1 gcd(a,p)=1 ,这些数都与 p p 互质,得到 A = B A=B
将两个集合的元素分别相乘得 ( p 1 ) ! ( p 1 ) ! a p 1 ( m o d p ) (p-1)!\equiv(p-1)!a^{p-1}\pmod p
a p 1 1 ( m o d p ) \therefore a^{p-1}\equiv1\pmod p

求乘法逆元

因为 a p 1 1 ( m o d p ) a^{p-1}\equiv1\pmod p ,那么 a a p 2 1 ( m o d p ) a\cdot a^{p-2}\equiv1\pmod p
所以 a p 2 a^{p-2} 就是 a a 关于模 p p 的乘法逆元。

欧拉定理

费马小定理是欧拉定理的一种特殊情况。
a , n a,n 为正整数,且 a , n a,n 互质,即 g c d ( a , n ) = 1 gcd(a,n)=1 ,则有:
a φ ( n ) 1 ( m o d n ) a^{\varphi(n)}\equiv1\pmod n

证明过程参考费马小定理
a a n n 互质时,可用欧拉定理降幂。
a b m o d &ThinSpace;&ThinSpace; n = a b m o d &ThinSpace;&ThinSpace; φ ( n ) m o d &ThinSpace;&ThinSpace; n a^b\mod n=a^{b\mod\varphi(n)}\mod n

一般地, b φ ( n ) b\geqslant\varphi(n) 时:
a b m o d &ThinSpace;&ThinSpace; n = a b m o d &ThinSpace;&ThinSpace; φ ( n ) + k φ ( n ) m o d &ThinSpace;&ThinSpace; n , k N a^b\mod n=a^{b\mod\varphi(n)+k\varphi(n)}\mod n,k\in N^*
上帝与集合的正确用法(NKOJ 5076)

问题描述
根据一些书上的记载,上帝的一次失败的创世经历是这样的:
第一天, 上帝创造了一个世界的基本元素,称做元。
第二天, 上帝创造了一个新的元素,称作 α \alpha α \alpha 被定义为元构成的集合。容易发现,一共有 2 2 种不同的 α \alpha
第三天, 上帝又创造了一个新的元素,称作 β \beta β \beta 被定义为 α \alpha 构成的集合。容易发现,一共有 4 4 种不同的 β \beta
第四天, 上帝创造了新的元素 γ \gamma γ \gamma 被定义为 β \beta 的集合。显然,一共会有 16 16 种不同的 γ \gamma
如果按照这样下去,上帝创造的第四种元素将会有 65536 65536 种,第五种元素将会有 2 65536 2^{65536} 种。这将会是一个天文数字。
然而,上帝并没有预料到元素种类数的增长是如此的迅速。他想要让世界的元素丰富起来,因此,日复一日,年复一年,他重复地创造着新的元素……
然而不久,当上帝创造出最后一种元素 θ \theta 时,他发现这世界的元素实在是太多了,以致于世界的容量不足,无法承受。因此在这一天,上帝毁灭了世界。
至今,上帝仍记得那次失败的创世经历,现在他想问问你,他最后一次创造的元素 θ \theta 一共有多少种?
上帝觉得这个数字可能过于巨大而无法表示出来,因此你只需要回答这个数对 p p 取模后的值即可。
你可以认为上帝从 α \alpha θ \theta 一共创造了 1 0 9 10^9 次元素,或 1 0 18 10^{18} 次,或者干脆 \infin 次。
一句话题意:求 2 2 2 2 2 . . . 2^{2^{2^{2^{2^{...}}}}} p p 取模后的值。

输入格式
接下来 T T 行,每行一个正整数 p p ,代表你需要取模的值。

输出格式
T T 行,每行一个正整数,为答案对 p p 取模后的值。

样例输入
3
2
3
6

样例输出
0
1
4

提示
T 1000 , p 1 0 7 T\leqslant 1000,p\leqslant10^7

这是一道休闲题。

typedef long long LL;
LL phi(LL x){
  LL ans=x;
  for(LL i=2;i*i<=x;i++)if(!(x%i)){
    ans-=ans/i;
    while(!(x%i))x/=i;
  }
  if(x>1)ans-=ans/x;
  return ans;
}
LL Pow(LL a,LL b,LL c){
  LL ans=1;a%=c;
  while(b){
    if(b&1)ans=(ans*a)%c;
    a=(a*a)%c,b>>=1;
  }
  return ans;
}
LL calc(LL p){return p==1?0:Pow(2,calc(phi(p))+phi(p),p);}
int main(){
  LL t,p;
  read(&t);
  while(t--){read(&p);write(calc(p),"\n");}
  return 0;
}

猜你喜欢

转载自blog.csdn.net/PHenning/article/details/89047432