你们要的欧拉欧拉欧拉欧拉终于来了
欧拉函数
我们用 φ(n)来表示欧拉函数
它等于<=n的数中与n互质的数的数目(1姑且认为与任何数互质吧)
首先当然是大家都擅长的暴力了,我们知道,两个数互质就是gcd=1,所以就有
int phi(int n)
{
int ans=0;
for(int i=1;i<=n;i++)
if(gcd(i,n)==1)
ans++;
return n;
}
但是很多时候暴力是出不了奇迹的,所以我们需要更好的方法
很多时候我们思考问题要学会逆向思维,只要把不与n互质的数去掉的话剩下的不就是与n互质的了。还记得之前说过的定理吗,在讲线筛的时候,任何合数都能拆成n个素数的乘积。所以只要把小于n的n的所有素因数的倍数去掉就好啦,是不是很简单哇。具体做法就算简单容斥啦(此时,我终于想起了没有做容斥的博客,但是问题不大)
比如说24,它的素因数有2,3
小于等于24&&2的倍数:24/2=12
小于等于24&&3的倍数:24/3=8
2和3的倍数24/(2 * 3)
需要去除的数为24 *(1/2-1/6+1/3)
φ(24)=24(1-1/2-1/3+1/6)=24(1-1/2)(1-1/3)=8
再比如三个素数的2*3*5=30
φ(30)=30(1-1/2)(1-1/3)(1-1/5)=8
至于为什么具体转到容斥定理(还没写)
于是我们就可以有新的写法了
int phi(int n)
{
int ans=n;
for(int i=2;i*i<=n;i++)
{
//由于任何一个合数都至少有一个不大于根号n的素因子,所以只需遍历到根号n即可
if(n%i==0)
{
ans = ans/i*(i-1);
//防溢出
while(n%i==0)n/=i;
//使n的因子没有素数i的倍数
}
}
if(n>1)
ans=ans/n*(n-1);
//如果n最终是素数的话会跳出循环,没有计算,所以这里还要再判断一次
return ans;
}
聪明的同学们可能已经发现了,这东西是可以打表的
遍历一遍,只要遍历到素数的话它的所有倍数(包括它本身)都除以它乘它-1既/i*(i-1)
int phi[N];
void Euler()
{
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);
}
}
}
}
复杂度和埃筛差不多,O(nlnln n)
然后提一下欧拉函数的一些性质
1.若p为质数,φ ( p)=p-1
因为小于质数p的数都与p互质
2.若i mod p = 0,且p为质数,则φ( i * p ) = φ(i) *p
ϕ ( i ) = i ∗ ( 1 − 1 a ) ∗ ( 1 − 1 p ) \phi(i)=i*(1-\frac{1}{a})*(1-\frac{1}{p}) ϕ(i)=i∗(1−a1)∗(1−p1)
ϕ ( i ∗ p ) = i ∗ p ∗ ( 1 − 1 a ) ∗ ( 1 − 1 p ) = ϕ ( i ) ∗ p \phi(i*p)=i*p*(1-\frac{1}{a})*(1-\frac{1}{p})=\phi(i)*p ϕ(i∗p)=i∗p∗(1−a1)∗(1−p1)=ϕ(i)∗p
3.若i mod p ≠0,且p为质数, 那么 φ( i * p )=φ(i) * ( p-1 )
ϕ ( i ) = i ∗ ( 1 − 1 a ) ∗ ( 1 − 1 b ) \phi(i)=i*(1-\frac{1}{a})*(1-\frac{1}{b}) ϕ(i)=i∗(1−a1)∗(1−b1)
ϕ ( i ∗ p ) = i ∗ p ∗ ( 1 − 1 a ) ∗ ( 1 − 1 b ) ∗ ( 1 − 1 p ) = i ∗ ( 1 − 1 a ) ∗ ( 1 − 1 b ) ∗ ( p − 1 ) = ϕ ( i ) ∗ ( p − 1 ) \phi(i*p)=i*p*(1-\frac{1}{a})*(1-\frac{1}{b})*(1-\frac{1}{p})=i*(1-\frac{1}{a})*(1-\frac{1}{b})*(p-1)=\phi(i)*(p-1) ϕ(i∗p)=i∗p∗(1−a1)∗(1−b1)∗(1−p1)=i∗(1−a1)∗(1−b1)∗(p−1)=ϕ(i)∗(p−1)
4.对于n=p^k ,有 ϕ ( n ) = ( p − 1 ) ∗ p k − 1 \phi(n)=(p-1) * p^{k-1} ϕ(n)=(p−1)∗pk−1
ϕ ( n ) = ϕ ( p k − 1 ∗ p ) = ϕ ( p k − 1 ) ∗ p = . . . = ϕ ( p ) ∗ p k − 1 = ( p − 1 ) ∗ p k − 1 \phi(n)=\phi(p^{k-1}*p)=\phi(p^{k-1})*p=...=\phi(p)*p^{k-1}=(p-1)*p^{k-1} ϕ(n)=ϕ(pk−1∗p)=ϕ(pk−1)∗p=...=ϕ(p)∗pk−1=(p−1)∗pk−1
5.若gcd(n,m)=1, ϕ ( n ∗ m ) = ϕ ( n ) ∗ ϕ ( m ) \phi(n * m)=\phi(n) * \phi(m) ϕ(n∗m)=ϕ(n)∗ϕ(m)
n与m互质,质数互不相同
6. n = ∏ p i k i n=\prod p_i^{k_i} n=∏piki ,则有 ϕ ( n ) = n ∗ ∏ ( 1 − 1 p i ) \phi(n)=n * \prod (1-\frac{1}{p_i}) ϕ(n)=n∗∏(1−pi1)
p为质数,易得(真的易得吖)
7.若gcd(a,m)=1,则 a ϕ ( m ) ≡ 1 a^{\phi(m)} \equiv 1 aϕ(m)≡1 (mod m)
欧拉定理,下有证明
8.小于n且与n互质的数的和 S=n* ϕ ( n ) 2 \frac{\phi(n)}{2} 2ϕ(n);
易知,若i与n互质,则n-i与n也互质
若i与n不互质 gcd(i,n)=a > 0, (n-i)/a=n/a-i/a为整数,故a也为n-i的因数,故 gcd(n,n-i) != 1
所以有S = n* ϕ ( n ) 2 \frac{\phi(n)}{2} 2ϕ(n)
∑ i = d ∣ n ϕ ( d ) \ \ \ \ \sum_{i=d|n}{\phi(d)} ∑i=d∣nϕ(d)=n
ϕ ( n ) = ∑ d ∣ n μ ( d ) ∗ n d \phi(n)=\sum_{d|n}\mu(d)*\frac{n}{d} ϕ(n)=∑d∣nμ(d)∗dn
由性质1 2 3 可得一种更快得筛法
const int N = 1e6+10;
int phi[N],prime[N];
int tot;
void Euler()
{
phi[1] = 1;
for(int i = 2; i < N;i++)
{
if(!phi[i])
{
phi[i]=i-1;
prime[tot++];
}
for(int j=0;j<tot&&1ll*i*prime[j]<N;j++)
{
if(i%prime[j])
phi[i*prime[j]]=phi[i]*(prime[j]-1);
else
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
}
原理和线筛差不多就不多累赘了
欧拉定理
当a,m互质时, a ϕ ( m ) ≡ 1 ( m o d m ) a^{\phi(m)}\equiv1 (mod\ m) aϕ(m)≡1(mod m)
枚举小于m与m互质的数 x 1 , x 2 , . . . , x ϕ ( m ) x_1,x_2,...,x_{\phi(m)} x1,x2,...,xϕ(m)
令 p i = a ∗ x i p_i=a*x_i pi=a∗xi
则对于 i ! = j , 有 p i m o d m ! = p j m o d m i!=j ,有 p_i \ mod \ m \ != \ p_j \ mod \ m i!=j,有pi mod m != pj mod m
$ p_i-p_j=a(x_i-x_j)$
因为a与m互质, x i x_i xi与m互质,所以 a ( x i − x j ) a(x_i-x_j) a(xi−xj)与m互质
既 ( p i − p j ) m o d m ! = 0 (p_i-p_j)mod\ m !=0 (pi−pj)mod m!=0
所以有 p i m o d m ! = p j m o d m p_i \ mod \ m \ != \ p_j \ mod \ m pi mod m != pj mod m
因此,对于确定的i,有确定的j使 p i m o d    m = x j p_i \mod\ m = x_j pimod m=xj
且i对j是一一映射的
因此得 ∏ i = 1 ϕ ( m ) p i ≡ ∏ i = 1 ϕ ( m ) a ∗ x i ≡ a ϕ ( m ) ∗ ∏ i = 1 n x i ≡ ∏ i = 1 n x i ( m o d m ) \prod_{i=1}^{\phi(m)}p_i\equiv\prod_{i=1}^{\phi(m)}a*x_i\equiv a^{\phi(m)}*\prod_{i=1}^{n}x_i\equiv \prod_{i=1}^{n}x_i (mod\ m) ∏i=1ϕ(m)pi≡∏i=1ϕ(m)a∗xi≡aϕ(m)∗∏i=1nxi≡∏i=1nxi(mod m)
得证 a ϕ ( m ) ≡ 1 ( m o d m ) a^{\phi(m)}\equiv 1(mod\ m) aϕ(m)≡1(mod m)
拓展欧拉定理
a c ≡ { a c m o d ϕ ( m ) , g c d ( a , m ) = 1 a c , g c d ( a , m ) ! = 1 , c < ϕ ( m ) a c m o d ϕ ( m ) + ϕ ( m ) , g c d ( a , m ) ! = 1 , c > ϕ ( m ) ( m o d m ) a^c \equiv\begin{cases} a^{c \ mod\ \phi(m)} \ \ \ \ \ \ \ \ \ \ \ ,\ gcd(a,m)=1\\ a^c\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ,\ gcd(a,m)!=1,c<\phi(m)\\ a^{c\ mod\ \phi(m)+\phi(m)}\ \ \ ,\ gcd(a,m)!=1,c>\phi(m)\end{cases} \ \ \ \ \ (mod\ m) ac≡⎩⎪⎨⎪⎧ac mod ϕ(m) , gcd(a,m)=1ac , gcd(a,m)!=1,c<ϕ(m)ac mod ϕ(m)+ϕ(m) , gcd(a,m)!=1,c>ϕ(m) (mod m)
证明有缘的话会给出来的(咕咕咕)
看了这个后就不要再写出 a c ≡ ( a m o d p ) c m o d p a^c \equiv (a\ mod\ p)^{c\ mod\ p} ac≡(a mod p)c mod p(mod m)这种东西来了,这个是错的错的错的!
欧拉降幂
就是当指数爆炸(超64位整数,几百位甚至更多)时可以用拓展欧拉定理来处理c mod ϕ ( m ) \phi(m) ϕ(m)
int main()
{
ll a,c,p;
char b[100000];
cin>>a>>b>>p;
int l = strlen(b);
for(int i=0;i<l;i++)
c=(c*10+b[i]-'0')%p;
cout<<qpow(a,c%phi(p)+phi(p),p)<<endl;
return 0;
}