• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
nannandbk
博客园    首页    新随笔    联系   管理    订阅  订阅
[数论]同余、欧拉函数(含扩欧)和逆元

coresidual and Euler function and Inverse element

1.同余(coresidual)

1.1 定义和两个常见性质

\(a≡b(\bmod m)<==>m|b-a\)
\(a≡b(\bmod m),a≡b(\bmod n) ==> a≡b(\bmod[m,n])\)
\((k,m)=d,ka≡ka'(mod m) ==> a≡a'(\bmod \frac{m}{d})\)
特别的\((k,m)=1,ka≡ka'(\bmod m) ==>a≡a'(\bmod m)\)

2.线性同余方程

\(ax≡b(mod m),ax+my = b\)两者等价
一开始我们由\(mx≡0(mod m),ax≡b(mod m)\),然后对\(x\)前面的系数辗转相除即可
\(eg.\)
\(100x ≡ 0(mod 100) ①\)
\(87x ≡ 3(mod 100) ②\)
\(①-②\) $ 13x ≡ 97(\bmod 100)③$
$ (-3)\( \)②-6③$ \(9x ≡ 21(\bmod 100)④\)
$③-④ $ $ 4x ≡ 76(\bmod 100)⑤\( \)④5-2⑤$ $ x ≡ 69(\bmod 100)$

3.简化剩余系

所有的\(n\)满足\(0<n<=m,(n,m)=1\)构成了一个模m的简化剩余系

欧拉函数\(φ(m)\)
定义:小于m的正整数中与m互质的数的数目
记这样n的个数为\(φ(m)\)
特别的:如果\(p\)是素数,则\(φ(p)=p-1\)
\(φ(m) = mΠp|m(1-1/p)\)

\(eg.30\)中有多少互质的,既不是\(2\)的倍数,也不是\(3\)的倍数,也不是\(5\)的倍数
\(30-30/2-30/3-30/5+30/2/3+30/2/5+30/3/5-30/2/3/5=8\)
\(==>30*(1-1/2)*(1-1/3)*(1-1/5)\)
\(==>30*(1-1/2-1/3-1/5+1/6+1/10+1/15-1/30)\)

\(m以内p1^{e1}*p2^{e2}...pk^{ek}\)

\(==>m(1-1/p1)(1-1/p)...(1-1/pk)\)

4.欧拉定理

如果\((a,m)=1\),那么\(a^{φ(m)}≡1(\bmod m)\)
证明:当\(x\)取遍模\(m\)的化简剩余系时,\(ax\)也取遍模\(m\)的简化剩余系
集合\(P\)小于等于\(m\)的且与\(m\)互质的正整数集合\({x1,x2...xφ(m)}\)
――――\(xi\)与\(m\)互质,\(xi\)模\(m\)后各不相同

集合\(Q\)为{ \(ax1\)%\(m\),\(ax2\)%\(m\)...\(axφ(m)\)%\(m\) }

因为\(a\)与\(m\)互质,所以$a*xi \(%\)m\(也与\)m\(互质,即\)Q\(中各元素均与\)m$互质

\(x1x2…xφ(m) ≡ ax1ax2…axφ(m)(\bmod m)\)

\(x1x2…xφ(m)≡a^{φ(m)}(x1x2…xφ(m))(\bmod m)\)

\(a^{φ(m)} ≡ 1 (\bmod m)\)

即

\(x1x2…xφ(m)≡a^{φ(m)}(x1x2…xφ(m))(\bmod m)\)

\(a^{φ(m)} ≡ 1(\bmod m)\)

5.推论(扩展欧拉定理)

我们知道,对于\(a,m\)互质的情况:

当\((a,m)=1\)时,\(a^{\phi(m)} \bmod m= 1\)

\(a^b \bmod m\)可以转化为 \(a^{b \bmod \phi(m)} \bmod m\),因为每\(a^{\phi(m)} \bmod m = 1\)

接下来我们看不互质的情况:

考虑在不互质的情况下会不会有相似的结论呢?

背景:我们举个例子看看

image

先说扩欧的结论:

\(a^b \bmod m = a^{b \bmod \phi(m)+\phi(m)} \bmod m\) 当\(b >= \phi(m)\)时

感性的来说:

image

扩欧板子

例题1:BZOJ 3884, 上帝与集合的正确用法

给定一个数字\(p\),求

​ \(2^{2^2…}\bmod p\)

的值。

理解一下题意:

\(a1 = 2\)

\(ai = 2^{ai-1}\)

当\(ai\)无限大的时候我们知道\(ai \bmod p\)是一个定值

因为这个东西它不一定是互质的,我们只需要把它的指数 \(\bmod \phi(p)+\phi(p)\)求出来,比如说求出来是\(x\),那我们只需要求\(2^x \bmod p\)就行了,然后我们发现它的幂次又是相同的子问题。也就是想要知道指数\(\bmod \phi(m)\)是多少,就要知道这个指数的指数\(\bmod \phi(\phi(m))\)是多少

先说几个结论:

1.除了\(2\)以外,其他数的\(\phi(p)\)都是偶数

2.\(\phi(m)<=\frac{1}{2}m\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll p;
ll ksm(ll a,ll b,ll m)
{
	ll ans = 1,base = a;
	while(b>0)
	{
		if(b&1)
		{
			ans *= base;
			ans %= m;
		}
		base *= base;
		base%=m;
		b>>=1;
	}
	return ans;
}


ll calc(int p)
{
	if(p==1)return 0;
	int phip = p,q = p;
	for(int i = 2;i*i<=q;i++)
	{
		/*
		m以内p1^e1*p2^e2...pk^ek
		==>m(1-1/p1)(1-1/p2)...(1-1/pk)
		*/
		if(q%i==0)
		{
			phip = phip/i*(i-1);
			while(q%i==0)q/=i;
		}
	}
	if(q!=1)phip = phip/q*(q-1);
	return ksm(2,calc(phip)+phip,p);
}

void solve()
{
	cin>>p;
	cout<<calc(p)<<endl;
}

int main()
{
	int t;
	cin>>t;
	for(int i = 1;i<=t;i++)
	{
		solve();
	}
	return 0;
}

例题2:CF D. Power Tower

题意:

给定一个数列\(w_1,w_2,...,w_n\)和模数p,每次询问一个区间[l,r],求\(w_l^{w_{l+1}^{w_{l+2}^{{...}^{w_r}}}} \bmod p\)的值

如果你看不懂上面的式子,它其实是这样运算的:

\(x=w_r\),\(x=w_{r-1}^x\),...,\(x=w_l^x\)

题解:

想要知道\(w_l^{w_{l+1}^{w_{l+2}^{{...}^{w_r}}}} \bmod m\)是多少,就要知道它的指数\(\bmod \phi(m)\)是多少,像要知道它的指数\(\bmod \phi(m)\)是多少,就要知道它指数的指数\(\bmod \phi(\phi(m))\)是多少。

我们知道这个\(m\)迭代\(\log\)轮之后会变成\(1\),也就是说我们只需要关注前\(\log\)项,因为后面的是不会影响答案的。

对比上一个例题,上一个例题因为\(b\)一定是\(>\phi(m)\)的,那我们就可以无脑带公式:指数\(\bmod \phi(m)+\phi(m)\)就行了。

但这题,指数是有可能小于\(\phi(m)\)的,那我们每次\(solve(l,r,m)\),如果这个东西\(<m\)我们就返回它原来的值,否则返回模之后加上\(m\)的值.

比如\(x = solve(l+1,r,\phi(m))\),那么当前的值就是\(al^{x}\bmod m\),我们要看\(al^{x}\bmod m\)是不是真的\(<m\),如果是真的\(<m\)我们就返回它原来的值,否则返回模之后加上\(m\)的值。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 101000;
int n,q,m,p[100],a[N],t;
ll ksm(ll a,ll b,ll m)
{
	ll ans = 1,base = a;
	while(b>0)
	{
		if(b&1)
		{
			ans *= base;
			ans %= m;
		}
		base *= base;
		base%=m;
		b>>=1;
	}
	return ans;
}

ll phi(int p)
{
	int phip = p,q = p;
	for(int i = 2;i*i<=q;i++)
	{
		if(q%i==0)
		{
			phip = phip/i*(i-1);
			while(q%i==0)q/=i;
		}
	}
	if(q!=1)phip = phip/q*(q-1);
	return phip;
}

int solve(int l,int r,int x)
{
	int q = p[x];
	if(l==r)return a[l]<q?a[l]:(a[l]%q+q);
	if(q==1)return 1;
	int d = solve(l+1,r,x+1);
	int ans = ksm(a[l],d,p[x]);
	//看a[l]^d < q?
	bool isles = true;
	if(a[l]!=1)
	{
		if(d>=30)//2^30次方肯定>q了
			isles =  false;
		else if(pow(a[l],d)>=1e9)isles = false;
		else//pow算出的可能有误差
		{
			int  val = ksm(a[l],d,1e9+7);
			if(val>=q)isles = false;
		}
	}
	if(!isles)ans += q;
	return ans;
}



int main()
{
	cin>>n>>m;
	p[t++] = m;
	while(p[t-1]!=1)
	{
		p[t] = phi(p[t-1]);
		t+= 1;
	}
	for(int i = 1;i<=n;i++)
	{
		cin>>a[i];
	}
	cin>>q;
	while(q--)
	{
		int l,r;
		cin>>l>>r;
		//0表示mod p[0]
		cout<<solve(l,r,0)%m<<endl;
	}
	return 0;
}

欧拉函数筛法

//筛法:
int phi[3000001];
void phi_table(){
    //memset(phi,0,sizeof(phi));
    phi[1]=1;
    for(int i=2;i<=3000000;i++){
        if(!phi[i])
        for(int j=i;j<=3000000;j+=i){
            if(!phi[j])
                phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
    }
}
//单个phi
ll phi(ll n) {
    ll ans = n;
    for(int i = 2; i*i <= n; i++) {
        if(n%i==0) {
            ans-=ans/i;
            while(n%i==0)
                n/=i;
        }
    }
    if(n > 1)   ans-=ans/n;
    return ans;
}
//线性筛phi
//记得在main里面先调用sieve
const int N=(1<<16)+5;
int n,tot,p[N];
bool flg[N];

void sieve(int n) {
    for(int i=2;i<=n;++i) {
        if(!flg[i]) p[++tot]=i;
        for(int j=1;j<=tot&&i*p[j]<=n;++j) {
            flg[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
}
long long phi(long long x) {
    long long ans=x;
    for(int i=1;i<=tot&&1LL*p[i]*p[i]<=x;++i) {
        if(x%p[i]) continue;
        ans=ans/p[i]*(p[i]-1);
        while(x%p[i]==0) x/=p[i];
    }
    if(x>1) ans=ans/x*(x-1);
    return ans;
}
//同时筛出质数表和欧拉函数表:
//O(nloglogn)
const int MAXN=1000000;
bool check[MAXN+10];
int phi[MAXN+10];
int prime[MAXN+10];
int tot;
void phi_and_prime_table(int N){
    memset(check,0,sizeof(check));
    phi[1]=1;
    tot=0;
    for(int i=2;i<=N;i++){
        if(!check[i]){
            prime[tot++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>N)
                break;
            check[i*prime[j]]=1;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else{
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
}

6.费马小定理(可以看作欧拉定理的特殊版本)

特别的当m是质数,φ(p) = p-1
\(a^{p-1} ≡ 1(\bmod p)\)

  1. 它可以用来判断大质数也就式Miller-Rabin质数判定
  2. 它可以用来进行费马小定理降幂也就是
    \(a^{k} ≡ a^{k mod (p-1)} (\bmod p)\)
  3. 求解逆元

7.逆元

1>定义

\(ax≡1(mod m)\)

\(x\)是\(a\)的逆元
除法的取模中运用
\(\dfrac{a}{b} ≡ a*b^{-1}(\bmod m)\)

2>求逆元

由于\(a^{φ(m)} ≡1(\bmod m)\)
那么\(a^{-1} ≡ a^{φ(m)-1}(\bmod m)\)
如果m为素数,那么答案为\(a^{m-2}\)
即:\(a^{p-1} ≡ 1(\bmod p)\)(费马小定理)\(==> a*a^{p-2}≡1(\bmod p)\)
用ksm求就ok

否则需将m(合数)分解,或解线性同余方程
\(a^{φ(m)} ≡ 1(\bmod m)\)

$ a{φ(m)-1}≡a(\bmod m)$

特别的:
a.求1~n的逆元
\(inv[i] = (p-p/i)*inv[p \bmod i]\bmod p\)

\(p = (p \bmod i)+\dfrac{p}{i}*i\)
\(0 ≡ (p \bmod i)+\dfrac{p}{i}*i(\bmod p)\)
\(-\dfrac{p}{i}*i ≡ (p \bmod i)\)
\(-\dfrac{p}{i} ≡ i^{-1}(p \bmod i)\)
\(-\dfrac{p}{i}*(p \bmod i)^{-1} ≡ i^{-1}\)

可以看出\(i\)的逆元可以有\(p \mod i\)的逆元逆推得到

需要将\(1\)的逆元初始化为\(1\),因为\(1^{-1}=1^{p-2}\)%\(p = 1\)

注意负数取模,\(-\lfloor\frac{p}{i}\rfloor\)对\(p\)取模需要先将负数\(+p\)变为正数在进行取模操作

//求1~n的逆元
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1e7+10;
ll inv[N],n,p;
int main()
{
	cin>>p>>n;
	inv[1] = 1;
	ll ans = 1;
	for(int i = 2;i<=n;i++)
	{
		inv[i] = (p-p/i)*inv[p%i]%p;
		ans = ans^inv[i];
	}
	cout<<ans<<endl;
	return 0;
}

inv2..待补充

posted on 2023-06-17 09:00  nannandbk  阅读(103)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3