欧拉函数,广义欧拉定理

讲解博客

欧拉定理

如果 a a a n n n 互质, a φ ( n ) ≡ 1 ( m o d      n ) a^{\varphi(n)}≡1(\mod \ n) aφ(n)1(mod n) φ ( n ) \varphi(n) φ(n) n n n 欧拉函数

威尔逊定理

p p p 是质数时, ( p − 1 ) ! ≡ 1 ≡ − 1 ( m o d      n ) (p-1)!≡1≡-1(\mod \ n) (p1)!11(mod n) ( p − 2 ) ! ≡ 1 ( m o d      n ) (p-2)!≡1(\mod \ n) (p2)!1(mod n)
等价于,如果 p p p 是质数,则 ( ( p − 1 ) ! + 1 )   %   p   = 0 ((p-1)!+1) \ \% \ p \ = 0 ((p1)!+1) % p =0
n n n 是质数, ( n − 1 ) !   % n = 1 (n-1)! \ \% n=1 (n1)! %n=1
n n n 是合数,除 n = 4 n=4 n=4 以外, ( n − 1 ) !   % n = 0 (n-1)! \ \% n = 0 (n1)! %n=0

欧拉函数

就是对于一个正整数 n n n,满足 x < n ( x ∈ [ 1 , n ) x<n(x \in[1,n) x<n(x[1,n) g c d ( n , x ) = 1 gcd(n,x) = 1 gcd(n,x)=1 (包括 1 1 1)的 x x x 的个数,记作 φ ( n ) φ(n) φ(n)
欧拉函数通式:
φ ( x ) = x ∗ ∏ i = 1 n ( 1 − 1 p i ) \varphi(x)=x*\prod_{i=1}^{n}(1-\frac{1}{p_i}) φ(x)=xi=1n(1pi1)
其中 p 1 , p 2 … … p n p1, p2……pn p1,p2pn n n n 的所有质因数, n n n 是不为 0 0 0 的整数。 φ ( 1 ) = 1 φ(1)=1 φ(1)=1(唯一和 1 1 1 互质的数就是 1 1 1 本身)。

性质:

  1. 对于质数 p p p φ ( p ) = p − 1 φ( p) = p - 1 φ(p)=p1。注意 φ ( 1 ) = 1 φ(1)=1 φ(1)=1
  2. m , n m,n m,n 互质 φ ( m n ) = φ ( m ) ∗ φ ( n ) φ(mn)=φ(m)*φ(n) φ(mn)=φ(m)φ(n)
  3. p p p 为质数且 i m o d    p = 0 i \mod p = 0 imodp=0, 那么 φ ( i ∗ p ) = φ ( i ) ∗ p \varphi(i * p)=\varphi(i) * p φ(ip)=φ(i)p
  4. n n n奇数时, φ ( 2 n ) = φ ( n ) φ(2n)=φ(n) φ(2n)=φ(n)
  5. n > 2 n > 2 n>2 时,所有 φ ( n ) φ(n) φ(n) 都是偶数
  6. n > 6 n > 6 n>6 时,所有 φ ( n ) φ(n) φ(n) 都是合数
  7. 欧拉定理:对于互质的正整数 a a a n n n ,有 a φ ( n ) ≡ 1 m o d    n a^{φ(n)} ≡ 1 \mod n aφ(n)1modn
  8. 费马小定理:若 p p p 是质数,则 a p − 1 ≡ 1 m o d    p a^{p-1}≡1 \mod p ap11modp
  9. 欧拉定理推论:小于等于 n n n 的数中,与 n n n 互质数的加和为: φ ( n ) ∗ n 2 ( n > 1 ) φ(n)*\frac{n}{2} (n>1) φ(n)2n(n>1)

事实上,根据性质 2 , 3 2,3 2,3 ,结合唯一分解定理,我们可以推出一个结论
先说说推导过程
根据唯一分解定理: n = p 1 q 1 p 2 q 2 p 3 q 3 . . . p n q k n=p_1^{q_1}p_2^{q_2}p_3^{q_3}...p_n^{q_k} n=p1q1p2q2p3q3...pnqk
结合性质 2 2 2 可以得到 φ ( n ) = φ ( p 1 q 1 ) φ ( p 2 q 2 ) φ ( p 3 q 3 ) . . . φ ( p n q k ) \varphi(n)=\varphi(p_1^{q_1})\varphi(p_2^{q_2})\varphi(p_3^{q_3})...\varphi(p_n^{q_k}) φ(n)=φ(p1q1)φ(p2q2)φ(p3q3)...φ(pnqk)
因为 p 1 q 1 = p 1 ∗ p 1 q 1 − 1 p_1^{q_1}=p_1 * p_1^{q_1-1} p1q1=p1p1q11,显然符合性质 3 3 3 p 1 p_1 p1 是质数, 并且 p 1   %   p 1 = 0 p_1 \ \% \ p_1=0 p1 % p1=0
因此 φ ( p 1 q 1 ) = φ ( p 1 q 1 − 1 ) ∗ p 1 = φ ( p 1 q 1 − 2 ) ∗ p 1 2 = . . . = φ ( p 1 ) ∗ p 1 q 1 − 1 = ( p 1 − 1 ) ∗ p 1 q 1 − 1 \varphi(p_1^{q_1})=\varphi(p_1^{q_1-1}) * p_1=\varphi(p_1^{q_1-2})*p_1^2=...=\varphi(p_1)*p_1^{q_1-1}=(p_1-1) * p_1^{q_1-1} φ(p1q1)=φ(p1q11)p1=φ(p1q12)p12=...=φ(p1)p1q11=(p11)p1q11

求一个数的欧拉函数

O ( s q r t ( n ) ) O(sqrt(n)) O(sqrt(n))
code:

//直接求解欧拉函数  
  int euler(int n){ //返回euler(n)   
       int res = n, a = n;  
       for(int i = 2; i * i <= a; ++i){  
           if(a % i == 0){  
               res = res / i * (i - 1);//先进行除法是为了防止中间数据的溢出   
               while(a % i == 0) a /= i;  
           }  
       }  
      if(a > 1) res = res / a * (a - 1);  
      return res;  
}

求1~n每个数的欧拉函数

普通筛法: O ( n l o g n ) O(nlogn) O(nlogn)
code:

void Init(){     
     euler[1] = 1;    
     for(ll i = 2; i < maxn; ++i)    
        if(!euler[i])    
           for(ll j = i; j < maxn; j += i){
           	if(!euler[j]) euler[j] = j; 
            euler[j] = euler[j] / i * (i - 1);//先进行除法是为了防止中间数据的溢出
		   }	
}

线性筛法:
类似与筛素数,我们在这里利用欧拉函数是积性函数这个性质来筛 φ ( n ) φ(n) φ(n)
这个筛法比上边快好几倍, m a x n maxn maxn 1 e 7 1e7 1e7 秒出结果
线性筛法证明
code:

int cnt;
int prime[maxn],phi[maxn];
bool vis[maxn];
void Euler_sieve (int n)
{
	phi[1] = 1;
	for (int i = 2; i <= maxn - 9; ++i){
		if (!vis[i])	prime[++cnt] = i, phi[i] = i - 1;
		for (int j = 1; j <= cnt && i * prime[j] <= maxn - 9; ++j){
			vis[i * prime[j]] = true;
			if (i % prime[j] == 0){	phi[i * prime[j]] = phi[i] * prime[j];break;}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
		}
	}
} 

欧拉定理

内容:对任意两个正整数 a , n a,n a,n,若两者互质,则: a φ ( n ) ≡ 1 ( m o d    n ) a^{φ(n)} ≡ 1 (\mod n ) aφ(n)1(modn)
注:作为对比,费马小定理 ( a p − 1 ≡ 1 ( m o d      p ) (a ^{p − 1} ≡ 1 ( \mod \ p ) ap11(mod p),其中 p p p 为质数),实际上就是欧拉公式的特殊情况。

欧拉降幂(广义欧拉定理)

引出:求解 a b m o d    p a^b \mod p abmodp,对于一定范围内我们可以利用快速幂求解,但是,当b大到一定程度时,利用快速幂这样的算法是无法在给定时间内求解的。
这时我们引入欧拉降幂算法,这个算法的特点就是降低幂方的值而不影响最终结果,使我们解决问题的时间缩短。

欧拉降幂公式:(无互质要求)
a b m o d      p = { a b , b < φ ( p ) a b m o d    φ ( p ) + φ ( p ) , b > = φ ( p ) a^b \mod \ p= \begin{cases} a^b,\quad b<\varphi(p) \\ \\ a^{b \mod \varphi(p) + \varphi(p)},\quad b>=\varphi(p) \end{cases} abmod p=abb<φ(p)abmodφ(p)+φ(p)b>=φ(p)
利用欧拉降幂公式求exponial(n)
在这里插入图片描述

洛谷模板题
b b b 的指数部分可以边乘边模,最后对 a b a^b ab 快速幂即可
i s d i g i t ( ) isdigit() isdigit() 函数的作用检查参数是否为十进制数字字符
code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a, b, m;
inline ll read(ll m){
	register ll x = 0, f = 0;
	char ch = getchar();
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)){
		x = x * 10 + ch - '0';
		if(x >= m) f = 1;
		x %= m; ch = getchar();
	}
	return x + (f == 1 ? m : 0);
}
ll phi(ll x)
{
	ll ans = x;
	for(ll i = 2; i * i <= x; ++i)
	{
		if(x % i == 0)
		{
			ans = ans / i * (i - 1);
			while(x % i == 0) x /= i;
		}
	}
	if(x > 1) ans = ans / x * (x - 1);
	return ans;
}
ll q_pow(ll a, ll n, ll mod){
	ll ans = 1;while(n){
		if(n & 1) ans=ans*a%mod;n>>=1;a=a*a%mod;
	}return ans;
}
int main()
{
	cin >> a >> m;
	b = read(phi(m));
	cout << q_pow(a, b, m);
	return 0;
}

上帝与集合的正确用法
题意:
输入一个数 p p p,求 f ( p ) = 2 2 2 2 . . . m o d    p f(p)=2^{2^{2^{2^{...}}}} \mod p f(p)=2222...modp,指数部分无限迭代
题意:
f ( p ) = 2 2 2 2 . . . m o d    p f(p)=2^{2^{2^{2^{...}}}} \mod p f(p)=2222...modp,指数无限下去
思路:
b > = φ ( p ) b>=\varphi(p) b>=φ(p) 时, a b = a b   % φ ( p ) + φ ( p )   %   p a^b=a^{b \ \% \varphi(p) + \varphi(p)} \ \% \ p ab=ab %φ(p)+φ(p) % p,因为指数无限迭代,显然满足公式
于是我们可以设 f ( p ) = 2 2 2 2 . . . m o d    p f(p)=2^{2^{2^{2^{...}}}} \mod p f(p)=2222...modp,那么有 f ( 1 ) = 0 f(1)=0 f(1)=0
所以 f ( p ) = 2 2 2 2 . . . m o d    p = 2 ( 2 2 2 . . . % φ ( p ) + φ ( p ) ) m o d    p = 2 f ( φ ( p ) ) + φ ( p ) m o d    p f(p)=2^{ 2^{2^{2^{...}}}} \mod p=2^{(2^{2^{2^{...}}}\% \varphi(p) + \varphi(p))} \mod p =2^{f(\varphi(p)) + \varphi(p)} \mod p f(p)=2222...modp=2(222...%φ(p)+φ(p))modp=2f(φ(p))+φ(p)modp
接下来就把欧拉定理和快速幂的板子套上就可以了
注意这个题的指数部分始终是无穷大,指数部分 b b b 与 模数的 φ ( p ) \varphi(p) φ(p) 的关系是一定的,不用考虑变化
code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
ll ph(ll x)
{
    ll res=x,a=x;
    for(ll i=2;i*i<=x;i++)
    {
        if(a%i==0)
        {
            res=res/i*(i-1);
            while(a%i==0) a/=i;
        }
    }
    if(a>1) res=res/a*(a-1);
    return res;
}

ll quick_pow(ll a,ll b,ll mod)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}

ll f(ll p)
{
    if(p == 1) return 0;
    ll k = ph(p);
    return quick_pow(2, f(k) + k, p);
}
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ll p;scanf("%lld",&p);
        printf("%lld\n",f(p));
    }
    return 0;
}

简单数据结构1
思路:
树状数组(区间修改,单点查询)+欧拉降幂
欧拉降幂大约递归 l o g log log
注意指数 b b b 和模数 p p p 的关系不同时,对其的操作也不同。
考虑到欧拉降幂使用的条件,进行快速幂取模时不能直接用 %   m o d \% \ mod % mod,应使用下边的取模操作

inline ll Mod(ll x, ll mod)
{
	return x < mod ? x : x % mod + mod;
}

code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e7 + 9;
ll n, m;
int phi[maxn], cnt, p[maxn];
bitset <maxn> v;
int op, l, r, P;
void init(int n)
{
	phi[1] = 1;
	for(ll i = 2; i <= n; ++i)
	{
		if(!v[i]) p[++cnt] = i, phi[i] = i - 1;
		for(ll j = 1; j <= cnt && i * p[j] <= n; ++j)
		{
			v[i * p[j]] = 1;
			if(i % p[j] == 0){
				phi[i*p[j]] = phi[i] * p[j];break;
			}
			phi[i*p[j]] = phi[i] * phi[p[j]];
		}	
	}return;
}

ll tr[maxn];
inline void add(int i, ll k){
	while(i <= n) tr[i] += k, i += i & (-i); 
}
inline ll query(int i, ll ans = 0){
	while(i) ans += tr[i], i -= i & (-i);return ans;
}
inline ll Mod(ll x, ll mod){
	return x < mod ? x : x % mod + mod;
}
ll q_pow(ll a, ll n, ll mod, ll ans = 1){
	a = Mod(a, mod);
	while(n){
		if(n & 1) ans=Mod(ans*a, mod);a=Mod(a*a,mod);n>>=1;
	}return ans;
}

inline ll f(int l, int r, int p)
{
	ll b = query(l);
	if(p == 1 || l == r) return b < p ? b : b % p + p;
	return q_pow(b, f(l + 1, r, phi[p]), p);
}

void work()
{
	cin >> n >> m;
	for(int i = 1; i <= n; ++i){
		ll x;cin >> x;add(i,x);add(i+1,-x);
	}
	while(m--)
	{
		cin >> op >> l >> r >> P;
		if(op == 1) add(l, P), add(r + 1, -P);
		else cout << f(l, r, P) % P << "\n";
	}
}

int main()
{
	ios::sync_with_stdio(0);
	init(2e7);
	work();
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值