数论初步
一些定理
裴蜀定理
若关于 \(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;
}
}