同余 与 数论其他

一.定理

费马小定理&欧拉定理

  • \(p\) 为质数且 \(a \not \equiv 0\pmod p\),则 \(a^{p-1}\equiv 1\pmod p\).

  • \(\gcd(a,m)=1\),则 \(a^{\varphi(m)}\equiv 1\pmod m\).

  • (扩展欧拉定理)若 \(b\ge\varphi(p)\),则有 \(a^{b}\equiv a^{b\bmod \varphi(p)+\varphi(p) }\pmod p\).

二.算法

欧几里得算法

给定 \(a,b\),求 \(\gcd(a,b)\)

我们发现,有:

\[\gcd(a,b)=\begin{cases}a & b=0 \\ \gcd(b,a\bmod b) & b\not = 0\end{cases} \]

利用这个东西递归计算即可。

扩展欧几里得(exgcd)

  • \(g=\gcd(a,b)\),求解下列方程:\(ax+by=g\)

设计函数 exgcd(ll a,ll b,ll &x,ll &y)

\(b=0\) 时,我们解此时的方程 \(a_0x+b_0y=g=a_0\),只需令 \(x=1,y=0\) 即可。

若已经知道了 \(bx+(a\bmod b)y=g\) 的一组解 \(x_0,y_0\),如何借出方程 \(ax+by=g\) 的一组解?

\[\begin{aligned}bx_0+(a\bmod b)y_0&=bx_0+(a-\lfloor \frac{a}{b} \rfloor \cdot b)y_0 \\&=bx_0+ay_0- \lfloor \frac{a}{b} \rfloor \cdot by_0 \\&=a(y_0)+b(x_0-\lfloor \frac{a}{b} \rfloor \cdot y_0)\end{aligned}\]

于是我们就得到了一组解 \(x=y_0,y=x_0-\lfloor \frac{a}{b} \rfloor \cdot y_0\),不停地向上回溯即可解出原方程的解。

代码:

ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){ x=1,y=0;return a; }
	ll d=exgcd(b,a%b,x,y);
	ll z=x; x=y; y=z-y*(a/b);//妈妈生的!!a/b要带括号!!! 
	return d;
}

注:

方程 \(ax+by=c\) 当且仅当 \(\gcd(a,b)\,\mid \,c\) 时有解。

线性同余方程

求解同余方程 \(ax\equiv b\pmod m\)

只需解出 \(ax-my=b\) 的一组解即可,运用 exgcd 即可。

当且仅当 \(\gcd(a,m)\,\mid \,b\) 时有解。

//解同余方程 ax≡b(mod m)
ll TYFC(ll a,ll b,ll m){
	ll x,y,mm; 
	ll G=exgcd(a,m,x,y);
	if(b%G) return -1;
	x*=b/G;mm=m/G;
	return (x%mm+mm)%mm;
}

类欧几里得算法,万能欧几里得算法与 SB 树

单独写一篇博客了,在这里

乘法逆元

同余方程 \(ax\equiv 1\pmod m\) 的解 \(x = a^{-1}\) 记作 \(a\)\(m\) 的乘法逆元

\(m\) 为奇质数

此时由费马小定理 \(a^{m}\equiv a\pmod m\),两边同时除以 \(a^2\)\(a^{m-2}\equiv a^{-1}\pmod m\),于是直接快速幂就好。

如果要 \(O(n)\) 求出 \(1\sim n\) 得所有数逆元,可以处理处阶乘和阶乘逆元。

\(m\) 不为质数

要求 \(a\)\(m\) 互质时 \(a^{-1}\) 才存在。

可以试做方程 \(ax+my\equiv 1\pmod m\) 这个方程 \(x\) 的一个解。

于是使用 exgcd 解方程就行。

中国剩余定理

参考:蓝书、oi-wiki

用来求解以下方程组:

\[\begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_2 \pmod {m_2} \\ \vdots \\ x \equiv a_n \pmod {m_n} \end{cases} \]

其中满足 \(\forall m_i\),两两互质。

我们记 \(m = \prod\limits_{i=1}^{n}m_i\)\(M_i = \dfrac{m}{m_i}\);记 \(t_i\)\(M_i\)\(m_i\) 下的逆元,即为 \(M_it_i\equiv 1 \pmod {m_i}\) 的一个解。

于是我们有 \(x\) 的整数解:

\[x_0=\sum\limits_{i=1}^{n}a_iM_it_i \]

证明也很简单,考虑方程 \(x_0\equiv a_k \pmod {m_k}\),对于所有的 \(i\not = k\),显然 \(M_i = \dfrac{m}{m_i}\)\(m_k\) 的倍数,故 \(a_iM_it_i\equiv 0 \pmod {m_i}\)

而对于 \(a_kM_kt_k\) 项来说,因为 \(M_kt_k \equiv 1 \pmod {m_k}\),故 \(a_kM_kt_k \equiv a_k \pmod {m_k}\),方程组成立。

此时 \(x\) 的通解为 \(x = km+x_0\)

扩展中国剩余定理

上述情况下如果不保证 \(m_i\) 两两互质。

蓝书是这么做的:

假设求出了 \(x_{k-1}\) 满足前 \(k-1\) 个方程,记 \(M_{k-1} = \overset{k-1}{\underset{i=1}{\operatorname{lcm}}} \;m_i\),则前 \(k-1\) 个方程的通解为 \(x = x_{k-1}+tM_{k-1}\)

考虑第 \(k\) 个方程,相当于 \(x_{k-1}+tM_{k-1}\equiv a_k \pmod {m_k}\)。方程等价于 \(M_{k-1}t\equiv a_k-x_{k-1}\pmod {m_k}\),其中只有 \(t\) 是变量。

解这个方程得到 \(t\),于是有了前 \(k\) 个方程的解 \(x_k=x_{k-1}+tM_{k-1}\)

如此来 \(n\) 遍就求出了所有方程的解。其中任何一步如果不满足 \(\gcd(M_{k-1}, m_k)\mid (a_k-x_{k-1})\) 则无解。

阶与原根

参照这篇博客

一.定义

由欧拉定理,对于整数 \(a\) 和 正整数 \(m\),若有 \(\gcd(a,m)=1\),则:

\[a^{\varphi(m)}\equiv 1\pmod m \]

也就是说,满足 \(a^n\equiv 1\pmod m\) 的最小正整数 \(n\) 一定存在,这个 \(n\) 称作 \(a\) \(m\) 的阶,记作 \(\delta_m(a)\)

如果有 \(\delta_m(a)=\varphi(m)\),则称 \(a\)\(m\) 的原根

二.性质

\[\delta_m(a)\mid \varphi(m) \]

证明咕了。

当且仅当 \(m=1,2,4,p^n,2p^n\) 时,\(m\) 有原根。

证明咕了。

\(m\) 有原根,则 \(m\) 共有 \(\varphi(\varphi(m))\) 个原根。

证明咕了。

\(m\ge 3,\gcd(g,m)=1\),则当且仅当对于 \(\varphi(m)\) 的每一个素因子 \(p\),有:

\[g^{\frac{\varphi(m)}{p}} \not\equiv 1\pmod m \]

时,\(g\) 为模 \(m\) 的原根。

离线对数问题

求解方程 \(a^x\equiv b\pmod p\)

BSGS算法

此部分来源于算法竞赛进阶指南。

全称为 BabyStepGiantStep,适用于 \(\gcd(a,p)=1\)

为何必须限定 \(\gcd(a,p)=1\)?因为只有在满足 \(a,p\) 互质时,模 \(p\) 意义同余方程两边才能同时进行关于 \(a\) 的加法、乘法运算。

由欧拉定理,\(a^x\)\(\varphi(p)\) 次就会出现循环节,故解一定小于 \(p\)

设解为 \(x=i\cdot t-j\),其中 \(t=\lceil\sqrt{p} \rceil,0\le j < t\),则有:

\[a^{i\cdot t-j}\equiv b\pmod p \]

即:

\[a^{i\cdot t}\equiv b\cdot a^j\pmod p \]

我们枚举 \(j\in[0,t-1]\),将 \(b\cdot a^j\bmod p\) 插入一个 map 中。

然后我们枚举 \(i\in[0,t]\) ,计算 \(a^{i\cdot t}\bmod p\),在 map 中查找是否存在对应的 \(j\),更新答案即可。

时间复杂度 \(O(\sqrt p)\)

点击查看代码
ll BSGS(ll a,ll b,ll p){
	if(a%p==0){
		if(b%p==1&&a!=0) return 0;
		else if(b%p==0) return 1;
		else return -1;
	}
	map <ll,int> mp; mp.clear();
	b%=p;ll t=ceil(sqrt((double)p)),now=b;
	for(int j=0;j<t;j++){
		if(j) (now*=a)%=mod;
		mp[now]=j;
	}
	now=1;a=qpow(a,t,p);
	for(int i=0;i<=t;i++){
		if(i) (now*=a)%=mod;
		if(mp.find(now)!=mp.end()&&i*t-mp[now] >=0) return i*t-mp[now];  
	}return -1;
}

扩展BSGS算法

还是求解这个方程,但这里没有 \(\gcd(a,p)=1\)

我们做如下处理:

同余式不好处理,我们令:

\[a^x+np=b \]

\(t=\gcd(a,p)\)

\(t\nmid b\),无解,除非 \(b=1\) 时解为 \(x=0\)

\(t=1\),直接 BSGS 就行了。

其他情况下,我们让式子左右同时除以 \(t\)

\[\frac{a^x}{t}+\frac{np}{t}=\frac{b}{t} \]

即:

\[\frac{a}{t}a^{x-1}\equiv \frac{b}{t}\pmod {\frac{p}{t}} \]

由于此时 \(\dfrac{a}{t}\)\(\dfrac{p}{t}\) 互质,故 \(\dfrac{a}{t}\) 在模 \(\dfrac{p}{t}\) 意义下有逆元。由于 \(\dfrac{p}{t}\) 不是质数,费马小定理不适用,我们用 exgcd 求出逆元,于是有:

\[a^{x-1}\equiv \frac{b}{t}\cdot \left(\frac{a}{t}\right)^{-1}\pmod {\frac{p}{t}} \]

发现这个问题和原问题一模一样,于是递归求解。

递归层数不超过 \(\log n\) 级别。

点击查看代码
ll TYFC(ll a,ll m){
	ll x,y; exgcd(a,m,x,y);
	return (x%m+m)%m;
}
ll exBSGS(ll a,ll b,ll p){
	b%=p; if(b==1||p==1) return 0;
	ll t=gcd(a,p);
	if(b%t) return -INF;
	if(t==1){
		return BSGS(a,b,p);
	}
	ll inv=TYFC(a/t,p/t);
	return exBSGS(a,b/t*inv,p/t)+1;
}

高次剩余

\[\color{red}\text{咕咕咕咕咕咕咕咕咕} \]

二次剩余

单独写了博客

其他

斐波那契相关

单独写了博客

\(O(1) \gcd\)

不是,这玩意太邪门了。

我们记值域为 \(m\)\(t=\sqrt m\),于是可以 \(O(m)\) 预处理,\(O(1)\)\(\gcd\)

参考了这三篇博客:OneInDarkweixin_30414635
hhoppitree

证明去翻这几篇博客吧,我反正是通篇不写证明,有空再写。

一.引理

对于任意正整数 \(x\le m\),均能够把 \(x\) 分为 \(x=abc\),其中 \(a,b,c\) 这三个数,要么 \(<\sqrt m\),要么是质数。

二.算法流程

我们预处理这些东西:

  1. \(\sqrt m\) 以内的 \(\gcd\) 表,复杂度为 \(O(\sqrt m \cdot \sqrt m)=O(m)\)

代码:

for(int i=1;i<=t;i++){
	gcd[i][0]=gcd[0][i]=i;
	for(int j=1;j<=t;j++){
		gcd[i][j]=gcd[j%i][i];
	}
}
  1. \(m\) 以内正整数的分解。

对于正整数 \(x\),假设它的最小质因数为 \(v\)\(\dfrac{x}{v}\) 分解为 \(abc\),则我们对其中最小的一个乘以 \(v\),即可得到 \(x\) 的分解。

代码:

split[1][0]=split[1][1]=split[1][2]=1;
for(int i=2;i<=maxm-10;i++){
	ll minn=INF,mini;
	for(int j=0;j<3;j++){
		split[i][j]=split[i/v[i]][j];
		if(split[i][j] < minn) minn=split[i][j],mini=j;
	}
	split[i][mini] *= v[i];
}

接下来我们尝试实现 \(\gcd(x,y)\)

首先,对于 \(x,y\le \sqrt m\),直接返回算好的 \(\gcd\) 表。

我们将 \(x\) 分解为 \(abc\)(下述中记为 \(x_0x_1x_2\)),然后分别用每个数和 \(y\) 计算 \(\gcd\),再合并答案。

具体的,每局 \(i\in[0,3)\),对于 \(x\) 的一个分解 \(x_i\),若 \(x_i\le \sqrt m\),则我们直接计算 \(d=\gcd(x_i,y\bmod x_i)\);否则,\(x_i\) 一定是质数,则如果 \(y\bmod x_i=0\),取 \(d=x_i\),否则取 \(d=1\)

然后我们让 \(ans\leftarrow ans*d\)\(y\leftarrow\dfrac{y}{d}\),即可。

代码:

ll Gcd(ll x,ll y){
	if(x<=1010 && y<=1010) return ggcd[x][y];
	ll res=1,tmp;
	for(ll i=0;i<3;i++){
		if(split[x][i]==1) continue;
		if(split[x][i] <= 1010) tmp=ggcd[split[x][i]][y%split[x][i]];
		else if(y%split[x][i]==0) tmp=split[x][i];
		else tmp=1;
		res *= tmp;y/=tmp;
	}return res;
}
posted @ 2024-01-31 18:05  一匹大宝羊  阅读(33)  评论(0)    收藏  举报