数论初步

一些定理

裴蜀定理
若关于 \(x,y\) 的不定方程 \(ax+by=c\) 有解(\(a,b,c \in \mathbf{Z}\)),则 \(c \bmod \gcd(a,b) =0\)
费马小定理
\(p\) 为质数,且 \(\gcd(a,p)=1\) ,则 \(a^{p-1} \equiv 1 \pmod{p}\)
威尔逊定理
\(p\) 为质数,则 \((p-1)!\ \equiv -1 \pmod p\)
欧拉定理
\(\gcd(a,m)=1\) ,则 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)
扩展欧拉定理
\(a^b \equiv \begin{cases} a^{b \bmod \varphi(p)}, & \gcd(a,p)=1 \\ a^b, & \gcd(a,p) \neq 1,b<\varphi(p) \\ a^{b \bmod \varphi(p)+\varphi(p)}, & \gcd(a,p) \neq 1, b \geq \varphi(p) \end{cases} \pmod p\)

exgcd

求关于 \(x\)\(y\) 的方程 \(ax+by=\gcd(a,b)\) 的一组解。
\(ax_1+by_1=\gcd(a,b)\)\(bx_2+(a \bmod b)y_2=\gcd(b,a \bmod b)\)
因为 \(\gcd(a,b)=\gcd(b,a \bmod b)\)
所以 \(ax_1+by_1=bx_2+(a \bmod b)y_2\)
所以 \(ax_1+by_1=bx_2+(a-\lfloor \frac{a}{b} \rfloor \cdot b)y_2\)
\(bx_2+(a-\lfloor \frac{a}{b} \rfloor \cdot b)y_2=ay_2+b(x_2-\lfloor \frac{a}{b} \rfloor \cdot y_2)\)
所以 \(ax_1+by_1=ay_2+b(x_2-\lfloor \frac{a}{b} \rfloor \cdot y_2)\)
所以 \(x_1=y_2\)\(y_1=x_2-\lfloor \frac{a}{b} \rfloor \cdot y_2\)
注意到当 \(b=0\) 时令 \(x=1\) 即可得到解,以其为边界递归即可。

int exgcd(int a,int b,int &x,int &y)
{
	if(!b)
	{
		x=1,y=0;
		return a;
	}
	int r=exgcd(b,a%b,x,y),t=x;
	x=y,y=t-a/b*y;
	return r;
}

CRT

求解如下形式的方程组(其中,\(m_1,m_2,\cdots,m_k\) 两两互质):
\(\begin{cases} x & \equiv & a_1 \pmod{m_1} \\ x & \equiv & a_2 \pmod{m_2} \\ & \vdots \\ x & \equiv & a_k \pmod{m_k} \\ \end{cases}\)
\(M=\prod \limits_{i=1}^k m_i\)\(w_i=\frac{M}{m_i}\)\(w_i^{-1}\)\(w_i\) 在模 \(m_i\) 意义下的逆元。
\(x_{min}=\sum \limits_{i=1}^k a_iw_iw_i^{-1} \bmod M\)

for(int i=1;i<=k;i++)
{
	int w=M/m[i];
	int x=0,y=0;
	exgcd(w,m[i],x,y);
	if(x<0) x+=m[i];
	ans+=a[i]*w*x%M,ans%=M;
}

exCRT

考虑上面的方程组中模数不互质的情况。
设当前求解到第 \(i\) 个方程,前 \(i-1\) 个方程的最小解为 \(x\)\(\operatorname{lcm}(m_1,m_2,\cdots,m_k)=M\)
则前 \(i-1\) 个方程的通解为 \(x+tM\)
那么,现在要找到一个 \(t\) ,使 \(x+tM \equiv a_i \pmod{m_i}\)
这个式子显然是可以使用 exgcd 求解的。
用裴蜀定理判一下无解。

for(int i=1;i<=n;i++)
{
	int res=(a[i]-X%m[i]+m[i])%m[i];
	int x=0,y=0;
	int d=exgcd(M,m[i],x,y);
	if(res%d) puts("-1"),exit(0);
	X+=x*res/d*M;//算上倍数,更新答案
	M*=m[i]/d,X+=M,X%=M;
}

Lucas

对于质数 \(p\) ,有 \(\displaystyle \binom{n}{m} \equiv \displaystyle \binom{\lfloor \frac{n}{p} \rfloor}{\lfloor \frac{m}{p} \rfloor} \cdot \displaystyle \binom{n \bmod p}{m \bmod p} \pmod p\)
在模数不大且为质数时,可以使用它来递归算组合数。

int lucas(int n,int m,int p)
{
	if(!m) return 1;
	return lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}

代码中, C 函数为暴力算组合数。

exLucas

算模数非质数时的组合数。
先将模数 \(p\) 质因数分解,设 \(p=\prod \limits_{i=1}^k q_i^{a_i}\) (其中 \(q_i\) 为质数)。
可以构造出下面的同余方程组:
\(\begin{cases} \displaystyle \binom{n}{m} & \equiv & b_1 \pmod{q_1^{a_1}} \\ \displaystyle \binom{n}{m} & \equiv & b_2 \pmod{q_2^{a_2}} \\ & \vdots \\ \displaystyle \binom{n}{m} & \equiv & b_k \pmod{q_k^{a_k}} \\ \end{cases}\)
因为这个同余方程组的所有模数都互质,所以只要求出 \(b_{1 \cdots k}\) 即可用 CRT 求出 \(\displaystyle \binom{n}{m}\)
现在,问题转化为求 \(\displaystyle \binom{n}{m} \bmod p^k\) 的值(\(p\) 为质数) ,即 \(\frac{n!}{m!(n-m)!} \bmod p^k\) 的值。
但是,分母在模 \(p^k\) 意义下不一定有乘法逆元,所以要再进行一些转化。
\(n!\) 中包含 \(x\)\(p\) 因子, \(m!\) 中包含 \(y\)\(p\) 因子, \((n-m)!\) 中包含 \(z\)\(p\) 因子,
则原式可以转化为 \(p^{x-y-z}\dfrac{\dfrac{n!}{p^x}}{\dfrac{m!}{p^y}\dfrac{(n-m)!}{p^z}} \bmod p^k\)
现在,问题又转化为求 \(\frac{n!}{p^x} \bmod p^k\) 的值 (\(p\) 为质数)。
\(n!\) 进行转化:
首先,把 \(n!\) 中所有为 \(p\) 的倍数的乘数和非 \(p\) 的倍数的乘数分开,\(n!=(p \times 2p \times 3p \times \cdots)(1 \times 2 \times 3 \times \cdots)\)
因为 \(1\) ~ \(n\) 中有 \(\lfloor \frac{n}{p} \rfloor\)\(p\) 的倍数,所以进一步拆开,得 \(p^{\lfloor \frac{n}{p} \rfloor}(\lfloor \frac{n}{p} \rfloor)!\prod \limits_{i=1,i \bmod p \neq 0}^n i\)
因为模数为 \(p^k\) ,所以再把后半个式子每 \(p^k\) 个分成一组,得 \(p^{\lfloor \frac{n}{p} \rfloor}(\lfloor \frac{n}{p} \rfloor)!(\prod \limits_{i=1,i \bmod p \neq 0}^{p^k} i)^{\lfloor \frac{n}{p^k} \rfloor}(\prod \limits_{i=p^k \times \lfloor \frac{n}{p^k} \rfloor, i \bmod p \neq 0}^{n} i)\)
因为还要除以 \(p^x\) ,所以 \(p^{\lfloor \frac{n}{p} \rfloor}\) 一定没有了,但是, \((\lfloor \frac{n}{p} \rfloor)!\) 中为 \(p\) 的倍数的乘数也要除去。
\(f(x)=\frac{n!}{p^x}\) ,其中 \(x\) 同样代表 \(n!\) 中包含 \(p\) 因子的数目,
\(f(n)=f(\lfloor \frac{n}{p} \rfloor)(\prod \limits_{i=1,i \bmod p \neq 0}^{p^k} i)^{\lfloor \frac{n}{p^k} \rfloor}(\prod \limits_{i=p^k \times \lfloor \frac{n}{p^k} \rfloor, i \bmod p \neq 0}^{n} i)\) ,递归计算即可。
代回原式中,发现还有 \(p^{x-y-z}\) 无法计算,考虑如何计算 \(x,y,z\)
下面以 \(\frac{n!}{p^x}\) 中的 \(x\) 为例。
\(g(x)=\) 上面的 \(x\)
观察前面化出的阶乘的式子,即可得到 \(g(n)=g(\lfloor \frac{n}{p} \rfloor)+\lfloor \frac{n}{p} \rfloor\) ,同样递归计算即可。

int f(int x,int p,int P)//P=p^k
{
	if(!x) return 1;
	int sum=1;
	for(int i=1;i<=P;i++)
		if(i%p) sum*=i,sum%=P;
	sum=POW(sum,x/P,P);
	for(int i=x/P*P;i<=x;i++)
		if(i%p) sum*=i%P,sum%=P;
	return f(x/p,p,P)*sum%P;
}
int g(int x,int p)
{
	if(!x) return 0;
	return g(x/p,p)+x/p;
}
int C(int n,int m,int p,int P)
{
	return f(n,p,P)*inv(f(m,p,P),P)%P*inv(f(n-m,p,P),P)%P*POW(p,g(n,p)-g(m,p)-g(n-m,p),P)%P;
}

代码中, POW 为快速幂函数,inv 为求逆元函数。

BSGS

求解方程 \(a^x \equiv b \pmod p\) ,其中 \(a,p\) 互质。
\(x=At-B\)\(t\) 为定值),
\(a^{At-B} \equiv b \pmod p\)
因为 \(a,p\) 互质,所以 \(a^{At} \equiv ba^B \pmod p\)
可以枚举 \(B\) 的取值,存进 Hash 表中。
再枚举 \(A\) 的取值,判断 Hash 表中是否存在这个值,若存在,则找到了一个 \(x\) 的取值。
\(t=\lceil \sqrt p \rceil\) 时复杂度最优。
代码用 map 实现。

map <int,int> mp;
int t=ceil(sqrt(P));
int sum=b,s=1;
mp[sum]=0;
for(int i=1;i<=t;i++) sum*=a,sum%=P,s*=a,s%=P,mp[sum]=i;
sum=s;
for(int i=1;i<=t;i++)
{
	if(mp.count(sum)) printf("%lld",i*t-mp[sum]),exit(0);
	sum*=s,sum%=P;
}
puts("-1");

exBSGS

同样求解上面的方程,但是 \(a,p\) 不保证互质。
\(a,p\) 不互质时,不存在 \(a\) 在模 \(p\) 意义下的逆元,也就没有上面的推导。
考虑如何让 \(a,p\) 互质。
\(\gcd(a,p)=d_1\) ,方程两边同除以 \(d_1\) ,得到 \(\frac{a}{d_1} \cdot a^{x-1} \equiv \frac{b}{d_1} \pmod{\frac{p}{d_1}}\)
若当前还没有满足 \(a\) 与模数互质,则继续设 \(\gcd(a,\frac{p}{d_1})=d_2\) ,方程两边同除以 \(d_2\) ,得到 \(\frac{a}{d_1d_2} \cdot a^{x-1} \equiv \frac{b}{d_1d_2} \pmod{\frac{p}{d_1d_2}}\)
重复这样的操作,直到 \(a\) 与模数互质。
设进行了 \(k\) 次操作,每次操作时得到的 \(d\) 的乘积为 \(D\)
则当前方程转化为了 \(\frac{a^k}{D} \cdot a^{x-k} \equiv \frac{b}{D} \pmod{\frac{p}{D}}\)
此时,就可以用普通的 BSGS 求解了。
注意,每次操作过后要用裴蜀定理判一下无解,还要特判 \(x \leq k\) 的情况。

int BSGS(int x)
{
	mp.clear();
	int t=ceil(sqrt(P));
	int sum=b,s=1;
	mp[sum]=0;
	for(int i=1;i<=t;i++) sum*=a,sum%=P,s*=a,s%=P,mp[sum]=i;
	sum=x*s%P;
	for(int i=1;i<=t;i++)
	{
		if(mp.count(sum)) return i*t-mp[sum];
		sum*=s,sum%=P;
	}
	return -1;
}
int exBSGS()
{
	if(b==1||p==1) return 0;
	int k=0,sum=1;
	while(1)
	{
		int d=gcd(a,P);
		if(d==1) break;
		if(b%d) return -1;
		k++,b/=d,P/=d,sum*=a/d,sum%=P;
		if(sum==b) return k;
	}
	int ans=BSGS(sum);
	return (ans!=-1)*k+ans;
}

原根

:设 \(a,p\) 为两个正整数,且 \(\gcd(a,p)=1\) ,则使 \(a^x \equiv 1 \pmod p\) 成立的最小正整数 \(x\) ,即为 \(a\)\(p\) 的阶,记作 \(\text{ord}_p a\)
\(g,a\) 为两个正整数,且 \(\gcd(g,a)=1\) ,若 \(\text{ord}_a g=\varphi (a)\) ,则 \(g\)\(a\) 的一个原根。
若一个数有原根,则它一定可以表示为 \(2,4,p^k,2p^k\) 的形式(\(p\) 为奇质数,\(k\) 为任意正整数)。
\(g\)\(a\) 的原根,则对于任意 \(\varphi(a)\) 的质因子 \(p\) ,都有 \(g^{\frac{\varphi(a)}{p}} \not \equiv 1 \pmod a\)
\(g\)\(a\) 的最小原根,则集合 \(S=\{g^k | 1 \leq k \leq \varphi(a),\gcd(k,\varphi(a))=1\}\) 中的元素均为 \(a\) 的原根。
因此,一个数 \(a\)\(\varphi(\varphi(a))\) 个原根,且这些原根模 \(a\) 两两不同余。
同时,若一个数 \(a\) 存在原根,则它的最小原根是不大于 \(a^{\frac{1}{4}}\) 级别的。所以求最小原根时可以直接枚举。

int find(int x)
{
	int tot=0;
	int X=phi[x];
	for(int i=2;i*i<=X;i++)
		if(X%i==0)
		{
			a[++tot]=i;
			while(X%i==0) X/=i;
		}
	if(X>1) a[++tot]=X;
	for(int i=1;;i++)
	{
		bool r=true;
		if(POW(i,phi[x],x)!=1) r=false;//原根的定义 
		for(int j=1;j<=tot;j++)
			if(POW(i,phi[x]/a[j],x)==1)
			{
				r=false;
				break;
			}
		if(r) return i;
	}
}
void get(int x)
{
	int t=find(x),s=1;
	for(int i=1;i<=phi[x];i++)
	{
		s*=t,s%=x;
		if(gcd(i,phi[x])==1) ans[++sum]=s;
	}
}
posted @ 2021-03-04 15:00  BBD186587  阅读(146)  评论(0编辑  收藏  举报