『数论』
數論,一生之敵!
前言
今天 LJ 讲了一堆数论知识,于是自己整理了一下。
正文
扩展 gcd / exgcd
exgcd 其实是解决这样一个不定方程 \(ax+by=c\) 的,当然这个不定方程等价于 \(ax \equiv c \pmod p\) 。(很显然)
看到这里,你想到了什么?对,我们小学二年级就学过的 Bezout 定理(译作裴蜀定理或贝祖定理)。
Bezout 定理:若 \(a,b \in Z\), 则一定存在一对整数 \(x,y\) 满足
证明:
不妨将上式记为 \((1)\) ,记 \(d=\gcd(a,b)\) 。
若 \(a,b\) 中有一数为 \(0\),假设 \(a=0\), 则 \(d=b\) 。此时 \((1)\) 可化为 \(by=m\) 。它有整数解,当且仅当 \(m\) 是 \(b\) 的倍数。
\(\because\) \(x\) 可以是任意整数
\(\therefore\) 定理成立。
若 \(a,b\) 都不为 \(0\) 。
设 \(S\) 为 \(a+b\) 的最小正值(最小数定理)。
由带余除法: \(a=q\times S+r\)
\(\therefore\) \(r=a-q\times S=a-q(ax+by)=a(1-q\times x)-b(q\times y)\)
\(\because\) \(q,x,y \in Z\) \(\therefore\) \(r\) 也是 \((a,b)\) 的线性组合。
\(\because\) \(S\) 为 \(ax+by\) 的最小值 \(\therefore\) \(r=0\) \(\therefore\) \(S|a\) 。
同理可得: \(S|b\) 。
\(\therefore\) \(S|d\)
\(\because\) \(d|a,d|b\) \(\therefore\) \(d|(ax+by)\)
\(\therefore\) \(d|S\)
\(\therefore\) \(S=d\) \(\blacksquare\)
当然也可以用欧几里得算法去证。
由 Bezout 定理我们知道 \(ax+by=c\) 中 \(\gcd(a,b)|c\) 。
然后,很显然 \(\gcd(a,b)=\gcd(b,a \bmod b)\)
因而,我们可以得出 exgcd 的模板(求关于 \(x\) 的方程 \(ax \equiv 1 \pmod b\) 的最小正整数解):
#include<bits/stdc++.h>
#define FOR(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;
long long a,b,x,y;
inline long long read()
{
long long x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
void exgcd(long long a,long long b)
{
if(!b)
{
x=1,y=0;
return ;
}
exgcd(b,a%b);
long long tx=x;
x=y,y=tx-a/b*y;
}
int main()
{
a=read(),b=read();
exgcd(a,b);
x=(x%b+b)%b;
printf("%lld\n",x);
return 0;
}
(这段可能有点奇怪,因为是差不多半年前写的)
乘法逆元
定义:如果 \(ax \equiv 1 \pmod p\), 则称 \(a\) 关于 \(p\) 的乘法逆元为 \(x\)。
一般编程时用 inv 表示。
然后我们一看,这不就是上文的 ecgcd 吗?
乘法逆元多用于 除法取模 。
设 \(x\) 是 \(b\) 关于 \(p\) 的乘法逆元,则有 \(a/b \equiv ax \pmod p\) 。
有些题需要用到 \(1 \sim n\) 关于 \(p\) 的乘法逆元,我们发现,此时用 exgcd 时间复杂度不理想,于是诞生了一种时间复杂度为 \(O(n)\) 的 递推算法。
设 \(p=k \times i+r\), \((r < i,1<i<p)\) , 则有
两边同乘 \(i^{-1}+r^{-1}\) 得
移项得
于是我们就可以递推了,注意边界为 \(i^{-1}\equiv 1 \pmod p\) 。
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
欧拉函数 \(\varphi\)
定义:欧拉函数 \(\varphi(x)\) 表示不超过 \(x\) 且与 \(x\) 互质的正整数个数,欧拉函数为 积性函数 即当 \(n,m\) 互质时 \(\varphi(nm)=\varphi(n)\cdot \varphi(m)\) 。
积性函数的证明:见 command_block 神仙的 blog
表示:将 \(x\) 分解成 \(p_{1}^{k_1}\times p_{2}^{k_2} \times \cdots \times p_n^{k_n}\) ,则有
证明:
若 \(x=p\), \(p\) 表示质数,则 \(\varphi(x)=x-1\) ,这是显然的。
若 \(x=p^k\),则 \(x\) 以内的正整数只要没有 \(p\) 这个质因数就与 \(x\) 互质。那么,正难则反,与 \(x\) 不互质的数有 \(p,2 \cdot p,3\cdot p, \cdots ,p^{k-1}p\),共 \(p^{k-1}\) 个数,所以 \(\varphi(x)=p^k-p^{k-1}=p^{k}(1-\dfrac{1}{p})\)
若 \(x\) 为合数,则 \(x\) 可以分解为 \(p_{1}^{k_1}\times p_{2}^{k_2} \times \cdots \times p_n^{k_n}\)。由于欧拉函数是积性函数,所以
\(\blacksquare\)
那么代码也就呼之欲出了
int phi(int x)
{
int ans=x;
for(int i=2;i<=sqrt(x);i++)
if(x%i==0)
{
ans-=ans/i;
while(x%i==0) x/=i;
}
if(x>1) ans-=ans/x;
return ans;
}
\(\uparrow\) 求单个数的 \(\varphi\)
\(\downarrow\) 求 \(1\sim n\) 的 \(\varphi\)
前置知识:若 \(p |n\) 则 \(n\) 含有 \(nq\) 所有的质因子,所以 \(\varphi(np)=p\times n\prod \limits _{i=1}^{k} (1-\dfrac{1}{p_i})=p \times \varphi(n)\)
若 \(p\not| n\) 则 \(\varphi(np)=\varphi(p) \times \varphi(n)=(p-1)\times \varphi(n)\) .
bitset<2333> used;
int p[233],cnt;
long long phi[2333];
inline void getphi()
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!used[i])
p[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*p[j]<=n;j++)
{
int val=i*p[j];
used[val]=1;
phi[val]=phi[i]*(i%p[j]?p[j]-1:p[j]);
if(i%p[j]==0) break;
}
}
}
今天模拟赛做到一道需要欧拉函数的例题 CF870F Paths
可以用欧拉函数做的一些事情(更新中):
给定一个数 \(n\),求 \(1\sim n\) 中与 \(n\) 互质的数的和。
先证一个引理:若 \(\gcd(n,i)=1\) 则 \(\gcd(n,n-i)=1\)。
考虑反证。令 \(k=\gcd(n,n-i)\),且 \(k\not = 1\)。则 \(k \mid n,k \mid n-i\) 故 \(k \mid i\),那么 \(\gcd(i,n)=k\) 矛盾。
此时问题就变得十分简单,答案就是 \(\dfrac{n \times \varphi(n)}{2}\)。因为 \(i\) 和 \(n-i\) 总是成对出现。
欧拉定理
内容
\(a^{\varphi(m)}\equiv 1 \pmod m\),其中 \(\gcd(a,m)=1\)。
证明
设 \(p_1,p_2,\cdots,p_{\varphi(m)}\) 是 \(1\) 到 \(m\) 中,与 \(m\) 互质的数。
令 \(x_i=a\times p_i\),易发现 \(x_i\) 模 \(m\) 两两不同。
证明:我们考虑反证,若 \(x_i \equiv x_j \pmod m\),则 \(x_i-x_j \equiv 0 \pmod m\),即 \(a(p_i-p_j) \equiv 0 \pmod m\)。由于 \(\gcd(a,m)=1\), \(p_i,p_j \le m\), \(p_i-p_j\) 一定小于 \(m\),所以矛盾。
同时每一个 \(x_i\) 模 \(m\) 的结果均与 \(m\) 互质。
证明:依然是反证,若 \(x_i=km+r\) \((0\le r<m)\) 且 \(\gcd(r,m)\not = 1\)。\(x_i-km=r\),故而 \(x_i \equiv r \pmod m\),即 \(ap_i \equiv r \pmod m\),\(a,p_i\) 均与 \(m\) 互质, \(r\) 亦与 \(m\) 互质,矛盾。
由上面的两个性质可以得出, \(x_1,x_2,\cdots,x_{\varphi(m)}\) 模 \(m\) 的结果是 \(\varphi(m)\) 个不同的与 \(m\) 互质的数,那不就是 \(p_1,p_2,\cdots,p_{\varphi(m)}\) 这个集合。
所以有
即
所以
\(\blacksquare\)
费马小定理
内容: \(a^{p-1}\equiv 1 \pmod p\),其中 \(\gcd(a,p)=1\),\(p\) 为质数。
证明:欧拉定理的一个特例。
用途: 可以求上文的乘法逆元
扩展欧拉定理
内容:
证明:
分开来证。
情况 1 の 证明:
不妨设 \(c=k\varphi(m)+r\),其中 \(0\le r<m\)。
则 \(a^c=a^{\varphi(m)^k}\times a^r=a^{\varphi(m)^k}\times a^{c \bmod \varphi(m)}\)
由欧拉定理可知 \(a^{\varphi(m)}\equiv1 \pmod m\)。
所以 \(a^c \equiv a^{c \bmod \varphi(m)}\)。
情况 2 の 证明:显然。
情况 3 の 证明:
类似于欧拉函数部分的证明。
我们不妨从 \(a\) 的质因子 \(p\) 入手。
即证明 \(p^{ \left(c \bmod \varphi(m) \right)+ \varphi(m)}\equiv p^c \pmod m,c\ge \varphi(m)\)。
Case 1
若 \(\gcd(m,p)=1\),则为情况 1, \(p^c \equiv p^{c \bmod \varphi(m)} \pmod m\), 又因 \(p^{\varphi(m)}\equiv 1 \pmod m\), 所以 \(p^c \equiv p^{ \left(c \bmod \varphi(m) \right)+ \varphi(m)}\pmod m\)。
Case 2
若 \(p\) 为 \(a,m\) 的公因子,令 \(m=s \times p^r\) 且 \(\gcd(s,p)=1\),所以 \(\gcd(s,p^r)=1\)。
因为 \(\gcd(p^x-1,p^r)=1,1\le x\le r\) ( \(p^x-1\) 中没有 \(p\) 这个因子, \(p^r\) 只有 \(p\) 这个质因子),所以 \(\varphi(p^r)\ge r\)。
所以 \(\varphi(m)=\varphi(s) \times \varphi(p^r)\ge \varphi(p^r)\ge r\)。
由欧拉定理 \(p^{\varphi(s)}\equiv 1 \pmod s\),因欧拉函数是积性函数可知 \(\varphi(m)=\varphi(s)\times \varphi(p^r)\),所以 \(p^{\varphi(m)}\equiv 1 \pmod s\)
同时乘 \(p^r\) 可得 \(p^{r+\varphi(m)}\equiv p^r \pmod m\)
所以有 \(p^k \equiv p^{k-r}\times p^r \equiv p^{k-r}\times p^{r+\varphi(m)} \equiv p^{k+\varphi(m)}\pmod m, k \ge r\)
易发现该式可以「 套娃 」, \(p^k \equiv p^{k+x\varphi(m)},x \in \mathbb{N}^+\)
当 \(c < 2\varphi(m)\),\(c \bmod \varphi(m) + \varphi(m)=c\),结论显然成立。
当 \(c\ge 2\varphi(m)\),\(c \bmod \varphi(m) + \varphi(m) \ge \varphi(m)\ge c\),故对 \(p^ {c \bmod \varphi(m)+\varphi(m)}\) 进行 「 套娃 」,易得 \(p^ {c \bmod \varphi(m)+\varphi(m)}\equiv p^c \pmod m\)
(终于搞完了,看网上很多 blog 这里都说什么 显然/即,然后我就非常崩溃,于是用比较容易理解的话语证明了这个部分,不过也许是我太菜了,只有我觉得很不显然?)
证明完 \(p^{ \left(c \bmod \varphi(m) \right)+ \varphi(m)}\equiv p^c \pmod m,c\ge \varphi(m)\)。
接下来就可以得到 \({p^k}^c \equiv {p^k}^{ \left(c \bmod \varphi(m) \right)+ \varphi(m)} \pmod m\)。
那么将 \(a\) 分解为 \(p_1 ^{k_1}\times p_2^{k_2}\times \cdots \times p_x ^{k_x}\)
则有 \({p_i^{k_i}}^c\equiv {p_i ^ {k_i}}^{\left(c \bmod \varphi(m) \right)+ \varphi(m)} \pmod m\)
将这些式子全部乘起来,就有 \(a^c \equiv a^{\left(c \bmod \varphi(m) \right)+ \varphi(m)} \pmod m\)。
\(\blacksquare\)
例题:P5091 【模板】扩展欧拉定理,CF906D Power Tower(幂塔),P4139 上帝与集合的正确用法(较为简单的幂塔)
中国剩余定理/CRT
前言:
三人同行七十稀,五树梅花廿一枝,七子团圆正半月,除百零五便得知
小学奥数老师告诉我说这是 中国剩余定理,后来貌似在某个电视剧(《少年派》?)里面看到有人用这个东西。
内容 :
其中 \(a_i\) 互质,求 \(x\) 的最小正整数解。
解法:
令 \(A = \prod \limits_{i=1}^n a_i\),\(A_i=\dfrac{A}{a_i}\),\(t_i\) 为 \(m_i\) 的逆元。
可以构造出一个解 \(x= \sum \limits_{i=1}^k b_iA_it_i\)。
所以任意解 \(x_0=x+ k\times A\)。
故最小正整数解 \(x_{\min}= x_0 \bmod A\)。
证明:
比较显然。
先考虑构造 \(x=\sum \limits _{i=1}^n b_iA_i \times ?\) 。
把 \(x\) 代入第 \(i\) 条式子易发现除了 \(b_iA_i \times ?\) 其他的都被 \(\bmod\) 掉了,因为 \(\forall j \in [1,n],j\not = i\),都有 \(a_i|A_j\)。
那么就是要满足 \(b_iA_i\times ? \equiv b_i \pmod {a_i}\),而 \(b_iA_it_i\) 正好满足。
最小整数解 \(x_{\min}=\sum \limits_{i=1}^k b_iA_it_i \bmod A\) 又是为何?
\(a_i\) 两两互质,对于第 \(i\) 个式子可以得到任意解 \(x_0=x+ k \times a_i\)。故而最后合在一起就是 \(x_0=x+ k \times A\)。
所以最小正整数解 \(x_{\min}=\sum \limits_{i=1}^k b_iA_it_i \bmod A\)。
扩展中国剩余定理/exCRT
内容:
此时 \(a_i\) 不再互质,求 \(x\) 的最小整数解。
求解:
假设我们已经求出了前 \(k-1\) 个方程组成的同余方程组的解 \(x'\)。
令 \(M=\operatorname{lcm}(a_i),i\in \{1,2,\cdots ,k-1\}\),则其通解为 \(x'+t\times M\),这是显然的。
要使得 \(x'+t\times M\) 满足第 \(k\) 条同余方程,即找出一个整数 \(p\),使得 \(x'+p\times M \equiv b_k \pmod {a_k}\)。
即 \(p\times M \equiv b_k -x' \pmod {a_k}\),容易发现对于这个式子我们可以用 exgcd 求这个 \(p\)。
若无解,则整个同余方程组无解。
若有解,则前 \(k\) 个同余方程组成的方程组的解 \(x_k=x' +p \times M\)
这样一项一项递推下去,就得到了最终答案。
注意: 求 \(\operatorname{lcm}\) 的时候要注意有可能爆 long long,需要龟速乘。
#include<bits/stdc++.h>
#define FOR(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;
int n;
long long a[100005],b[100005];
inline long long read()
{
long long x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
inline long long mul(long long a,long long b,long long mod)
{
long long res=0;
while(b)
{
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;b>>=1;
}
return res;
}
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if(!b){x=1,y=0;return a;}
long long gcd=exgcd(b,a%b,x,y);
long long t=x;x=y;y=t-a/b*y;
return gcd;
}
inline long long excrt()
{
long long ans=b[1],M=a[1];
long long x,y;
for(int i=2;i<=n;i++)
{
long long B=(b[i]-ans%a[i]+a[i])%a[i];
long long gcd=exgcd(M,a[i],x,y),mod=a[i]/gcd;
if(B%gcd!=0) return -1;
x=mul(x,B/gcd,mod);
ans+=x*M;
M*=mod;
ans=(ans+M)%M;
}
return (ans+M)%M;
}
int main()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read(),b[i]=read();
//a[i] mod number
//b[i] left number
printf("%lld\n",excrt());
return 0;
}
原根
阶:若 \(\gcd(a,m)=1\),使 \(a^k \equiv 1 \pmod m\) 成立的最小的 \(k\),成为 \(n\) 关于模 \(m\) 的阶,记作 \(\delta_m(a)\) 或者 \(\operatorname{ord}_m a\)。
阶的一些性质:
- 「1」若 \(\delta_m(a)=k\),则 \(\displaystyle\delta_m(a^t)= \frac{k}{\gcd(t,k)}\),这是十分显然的。
- 「2」令 \(k=\delta_m(a)\),则 \(a^n \equiv 1 \pmod m\) 当且仅当 \(k\mid n\)。由欧拉定理可知 \(k\mid\varphi(m)\)。
- 「3」若\(a\equiv b \pmod m, \gcd(a,m)=1\),则 \(\delta_m(a)=\delta_m(b)\)。
- 「4」若 \(\gcd(a,m)=1\),那么 \(a^x \equiv a^y \pmod m\),的充分必要条件为 \(x \equiv y \pmod {\delta_m(a)}\)。
证明:令 \(x\le y\),则 \(a^{y-x}\equiv1 \equiv a^{\delta_m(a)} \pmod m\)。故而 \(\delta_m(a) \mid y-x\),所以 \(y \equiv x \pmod {\delta_m(a)}\)。
- 「5」\(a^0,a^1,\dots,a^{\delta_m(a)}\) 模 \(m\) 的值互不相等。
证明:反证,作差,略。
- 「6」\(ab \equiv 1 \pmod m,\gcd(a,m)=\gcd(b,m)=1\),则 $\delta_m(a)=\delta_m(b) $。
证明:令 \(\delta_m(a)=k\),则有 \((ab)^k\equiv 1 \pmod m\),而 \(a^k \equiv 1 \pmod m\) 的充要条件为 \(b^k \equiv 1\pmod m\)。
- 「7」若 \(n \mid m\),则 \(\delta_n (a)\mid \delta_m (a)\)。
证明:\(\because a^{\delta_m(a)}\equiv 1 \pmod m\) 且 \(n \mid m\) \(\therefore a^{\delta_m(a)}\equiv 1 \pmod n\)。由性质「2」可知 \(\delta_n(a)\mid \delta_m(a)\)。
- 「8」若 \(\gcd(m,n)=\gcd(a,mn)=1\),则 \(\delta_{mn}(a)=\operatorname{lcm}(\delta_m(a),\delta_n(a))\)。
证明:令 \(x=\delta_{mn}(a),y=\operatorname{lcm}(\delta_m(a),\delta_n(b))\)。
\(\because a^x \equiv 1\pmod {mn}\)
\(\therefore a^x \equiv 1 \pmod m,a^x \equiv 1 \pmod n\)
\(\therefore \delta_m(a)\mid x,\delta_n(a)\mid x\)
\(\therefore y\mid x\)
\(\because \delta_m(a)\mid y,\delta_n(a)|y\)
\(\therefore a^y\equiv 1\pmod m,a^y \equiv 1 \pmod n\)
\(\because \gcd(n,m)=1\)
\(\therefore a^y \equiv 1 \pmod {mn}\)
\(\therefore x \mid y\)
\(\therefore x=y\)
- 「9」若 \(\gcd(ab,m)=\gcd(\delta_m(a),\delta_m(b))=1\),则 \(\delta_m(ab)=\delta_m(a) \times\delta_m(b)\)。
证明:令 \(x=\delta_m(a),y=\delta_m(y),z=\delta_m(ab)\)。
\(\because a^x \equiv 1 \pmod m\) 且 \(b^y \equiv 1 \pmod m\)
\(\therefore (ab)^{xy}\equiv 1 \pmod m\) \(\therefore z \mid xy\)
\(\because a^x\equiv 1 \pmod m\) 且 \((ab)^z \equiv 1 \pmod m\)
\(\therefore a^{xz}\equiv 1 \pmod m\) 且 \((ab)^{xz}\equiv 1 \pmod m\)
\(\therefore b^{xz}\equiv 1 \pmod m\) \(\therefore y \mid xz\)
\(\because \gcd(x,y)=1\) \(\therefore y \mid z\) 同理可得 \(x|z\)
\(\therefore \operatorname{lcm}(x,y)=xy \mid z\)
\(\therefore z=xy\)
原根:
\(\gcd(g,m)=1\),若 \(\delta_m(g)=\varphi(m)\),则称 \(g\) 为 \(m\) 的一个原根。
判断是否存在原根:若 \(m\) 有原根,则 \(m\) 一定是以下形式:\(2,4,p^k,2p^k\)。这里 \(p\) 为奇素数,\(k\) 为正整数。
证明 OI-wiki 上有。不会。
原根的判定:
\(\gcd(g,m)=1\),设 \(p_1,p_2,\dots,p_k\) 是 \(\varphi(m)\) 的所有不同素因数,则 \(g\) 是 \(m\) 的原根当且仅当对于任意 \(\forall i \in[1,k]\),都有
$ g^{\frac{\varphi(m)}{p_i}} \not\equiv 1 \pmod m $。
证明:
令 \(q=\varphi(m)\),假设存在一个 \(t < q\) 使得 \(g^t \equiv 1 \pmod m\),且 \(\forall i \in [1,k]: g^{\frac{q}{p_i}}\not \equiv 1\)。
由 Bezout 定理可知,一定存在一组 \(k,x\) 满足 \(kt=xq+\gcd(t,q)\)。
由欧拉定理可知, \(g^q \equiv 1 \pmod m\)。故有:
又因 \(t<q\),故 \(\gcd(t,q)\le t <q\)。
故而 \(\gcd(t,q)\) 必定至少整除 \(g^{\frac{q}{p_1}},g^{\frac{q}{p_2}},\dots,g^{\frac{q}{p_k}}\) 其中的一个。
假设 \(\gcd(t,q) \mid g^{\frac{q}{p_i}}\),则有 \(g^{\frac{q}{p_i}}\equiv g^{\gcd(t,q)}\equiv 1 \pmod m\),矛盾。
假设不成立。
原根个数定理:集合 \(S=\{g^s \mid 1 \le s \le \varphi(m),\gcd(s,\varphi(m))=1\}\) 给出了 \(m\) 所有的原根。共有 \(\varphi(\varphi(m))\) 个模 \(m\) 两两不互余的原根。
大致证明:由「原根的定义」可知,\(g^s\) 是 \(m\) 的原根当且仅当 \(\delta_m(g^s)=\varphi(m)\)。由「阶的性质 1」可知 \(\delta_m(g^s)=\dfrac{\delta_m(g)}{\gcd(s,\varphi(m))}\)。故而 \(\gcd(s,\varphi(m))=1\)。
但是我有一个疑惑,为什么不会存在一个数 \(x\not = g^s\) 但是满足 \(\delta_m(x)=\varphi(m)\)。希望有神仙可以解答一下。
求所有原根:王元曾证明最小原根是不大于 \(\sqrt[4]{m}\) 级别的。故而最小原根是很小的。不妨枚举一个最小的 \(g\),然后枚举指数即可。
原根的一些性质:
「1」\(\displaystyle\prod _{s=1,s\bot\varphi(m)}^{\varphi(m)} g^s \equiv 1 \pmod m\)。原因见前「可以用欧拉函数做的一些事情」。
「2」\(\displaystyle \sum _{s=1,s\bot\varphi(m)}^{\varphi(m)} g^s \equiv \mu(m-1) \pmod m\)。目前不会。
代码:
#include<bits/stdc++.h>
#define FOR(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;
int tc,cnt;
int n,d;
int prime[100005],phi[1000006];
bitset<1000006> rt;
bitset<1000006> used;
vector<int> pfact;
vector<int> proot;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
inline void sieve(int n)
{
phi[1]=1;
for(int i=2;i<=n;i++)
{
if(!used[i]) prime[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&prime[j]*i<=n;j++)
{
used[i*prime[j]]=1;
if(i%prime[j]) phi[i*prime[j]]=phi[i]*(prime[j]-1);
else
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
}
}
rt[2]=rt[4]=true;
for(int i=2;i<=cnt;i++)
{
for(int j=1;1ll*j*prime[i]<=n;j*=prime[i]) rt[j*prime[i]]=1;
for(int j=2;1ll*j*prime[i]<=n;j*=prime[i]) rt[j*prime[i]]=1;
}
}
inline void divide(int x)
{
for(int i=1;prime[i]<=x;i++)
if(x%prime[i]==0)
pfact.push_back(prime[i]);
}
inline int gcd(int a,int b){return (!b)?a:gcd(b,a%b);}
inline int f(int base,int y,int mod)
{
int res=1,p=base;
while(y)
{
if(y&1) res=1ll*res*p%mod;
p=1ll*p*p%mod;
y>>=1;
}
return res;
}
int main()
{
tc=read();
sieve(1000000);
while(tc--)
{
n=read(),d=read();
if(rt[n])
{
pfact.clear();
proot.clear();
divide(phi[n]);
int gmin=0;
while(true)
{
gmin++;
bool flag=true;
if(gcd(n,gmin)!=1) continue;
for(int j=0;j<pfact.size();j++)
if(f(gmin,phi[n]/pfact[j],n)==1)
{
flag=false;break;
}
if(flag) break;
}
long long g=1;
for(int i=1;i<phi[n];i++)
{
g=g*gmin%n;
if(gcd(phi[n],i)==1) proot.push_back(g);
}
if(!proot.size()) proot.push_back(gmin);
sort(proot.begin(),proot.end());
printf("%d\n",phi[phi[n]]);
for(int i=d-1;i<phi[phi[n]]&&i<proot.size();i+=d)
printf("%d ",proot[i]);
puts("");
}
else puts("0\n");
}
return 0;
}
二次剩余
以下内容均默认模数 \(p\) 为奇质数。
内容:若有 \(x\) 满足 \(x^2\equiv n \pmod p\),则称 \(n\) 在模 \(p\) 意义下是二次剩余。说人话就是模意义开根。
解的数量:对于模 \(p\) 意义下的二次剩余 \(n\) 有几个解?
假设有多组解,其中两组分别为 \(x_1,x_2\)。那么有 \({x_1}^2 \equiv{x_2}^2 \pmod p\),移项得: \((x_1-x_2)(x_1+x_2) \equiv 0 \pmod p\)。
因为 \(p\) 为质数且 \(x_1 \not = x_2\),所以 \(x_1+x_2=0\),所以方程只有两个解,她们互为相反数。
那么我们还可以知道,每一对相反数都有一个二次剩余,且这些二次剩余互不相等。
故而二次剩余的数量恰为 \(\dfrac{p-1}{2}\),二次非剩余的数量与之相等。
欧拉准则:如何判断一个数是不是二次剩余?
假定 \(n \not = 0\)。
由费马小定理可得 \(n^{{p-1}} \equiv 1\pmod p\)。也就是说 \(n^{\frac{p-1}{2}}\) 是 \(1\) 开根的结果,故而 \(n^{\frac{p-1}{2}}\) 只能是 \(1\) 或 \(-1\)。
若 \(n\) 是二次剩余,则 \(n^{\frac{p-1}{2}}\equiv (x^2)^{\frac{p-1}{2}}\equiv x^{p-1}\equiv 1\pmod p\)。
若 \(n^{\frac{p-1}{2}}\equiv 1 \pmod p\),由于 \(p\) 为奇质数,则 \(n\) 必然能表示成 \(g^t\) 其中 \(g\) 为 \(p\) 的原根。那么 \(g^{t\frac{p-1}{2}}\equiv 1 \pmod p\) 所以 \(\varphi(p) \mid t\frac{p-1}{2}\),所以 \(t\) 一定是偶数。此时 \(x=g^{\frac{t}{2}}\)。故 \(n\) 是二次剩余。
上面证明了 \(n^{\frac{p-1}{2}}\equiv 1 \iff n\) 是二次剩余。又因为 \(n^{\frac{p-1}{2}}\) 只能等于 \(±1\),所以 \(n^{\frac{p-1}{2}}\equiv -1 \iff n\) 是二次非剩余。
Cipolla:
对于方程 \(x^2 \equiv n \pmod p\),先随机选出一个自然数 \(a\),使得 \(a^2-n\) 为二次非剩余,已证二次非剩余有 \(\frac{p-1}{2}\) 个,故而期望 \(2\) 次得到 \(a\)。接下来定义 \(\zeta^2 \equiv a^2 -n \pmod p\)。
再给出两个引理:
引理「1」:\(\zeta ^p \equiv -\zeta\)。
证明: \(\zeta^p \equiv \zeta\times (\zeta^2)^{\frac{p-1}{2}}\equiv \zeta\times (a^2-n)^{\frac{p-1}{2}}\equiv -\zeta \pmod p\)。
引理「2」: \((a+\zeta)^p \equiv a^p+\zeta^p\)
证明:二项式展开,除了 \(a^p\) 和 \(\zeta^p\) 两项外,其他项的系数都是 \(p\) 的倍数。
那么有 \((a+\zeta)^{p+1}\equiv n \pmod p\)。
证明如下:
\((a+\zeta)^{p+1}\equiv (a+\zeta)^p(a+\zeta)\),由引理「2」\((a+\zeta)^p(a+\zeta)\equiv (a^p+\zeta^p)(a+\zeta)\),由引理「1」\((a^p+\zeta^p)(a+\zeta)\equiv (a^p-\zeta)(a+\zeta)\)。由费马小定理 \(a^p\equiv a^{p-1}\times a\equiv a \pmod p\),故而 \((a^p-\zeta)(a+\zeta)\equiv (a-\zeta)(a+\zeta)\equiv a^2-\zeta^2\equiv n \pmod p\)。
所以 \((a+\zeta)^{\frac{p+1}{2}}\) 是一个解。
现在的问题就是 \((a+\zeta)^{\frac{p+1}{2}}\) 的“虚部”是否为 \(0\)?事实上是不会的。
证明:
假设存在 \((A+B\zeta)^2 \equiv n\) 且 \(B\not = 0\)。
那么就有 \(A^2+B^2(a^2-n) -2AB\zeta \equiv0 \pmod p\)
右边“虚部”为 \(0\) 则左边“虚部”一定也为 \(0\)。因为 \(B\not= 0\),所以 \(A\equiv 0\),\((B\zeta)^2\equiv 0\),\(\zeta^2\equiv \dfrac{n}{B^2}\)。\(n,\dfrac{1}{B^2}\) 都是二次剩余,乘在一起也一定是二次剩余。所以 \(\zeta^2\) 是二次剩余,与前矛盾。故 \(B=0\),所以 \((a+\zeta)^{\frac{p+1}{2}}\) 的虚部是 \(0\)。
模板题代码:
#include<bits/stdc++.h>
#define FOR(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;
int n,tc,mod;
long long sqr;
struct cplx{
long long real,imag;
cplx(long long real=0,long long imag=0):real(real),imag(imag){}
};
inline cplx operator *(cplx x,cplx y)
{
return cplx((x.real*y.real+sqr*x.imag%mod*y.imag)%mod,(x.imag*y.real+x.real*y.imag)%mod);
}
inline cplx f(cplx x,int y)
{
cplx res=1;
while(y)
{
if(y&1) res=res*x;
x=x*x;y>>=1;
}
return res;
}
inline int F(int base,int y)
{
int res=1,p=base;
while(y)
{
if(y&1) res=1ll*res*p%mod;
p=1ll*p*p%mod;y>>=1;
}
return res;
}
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main()
{
srand(19260817);
tc=read();
while(tc--)
{
n=read(),mod=read();
n%=mod;
int x=F(n,(mod-1)>>1);
if(x==mod-1) puts("Hola!");
else if(!x) puts("0");
else
{
x=rand()%mod;
sqr=0;
while(!x||F((1ll*x*x+mod-n)%mod,(mod-1)>>1)==1) x=rand()%mod;
sqr=(1ll*x*x+mod-n)%mod;
int ans1=f(cplx(x,1),(mod+1)>>1).real;
int ans2=mod-ans1;
if(ans1>ans2) swap(ans1,ans2);
printf("%d %d\n",ans1,ans2);
}
}
return 0;
}
BSGS
北上广深好啊。
BSGS(Baby Step Giant Step),大步小步拔山盖世/北上广深算法。常用于求解离散对数问题。
可以在 \(O(\sqrt{p})\) 的时间内求解模方程
其中 \(\gcd(a,p)=1\)。方程的解 \(x\) 满足 \(0\le x\le \varphi(p)\)。
算法描述:
把 \(x\) 表示成 \(x=At-B\) 的形式,其中 $0\le A\le \max(t,\frac{p}{t}) $,$0\le B< \max(t,\frac{p}{t}) $,则有 \(a^{At-B}\equiv b \pmod p\),即 \(a^{At}\equiv ba^{B}\pmod p\)。
我们 枚举 \(B\),并计算 \(ba^B\) 将其放入 Hash 表中。
然后枚举 \(A\),在 Hash 表中查询 \(a^{At}\) 即可。
时间复杂度为 \(O(\max(t,\frac{p}{t}))\),显然 \(t\) 取 \(\sqrt{p}\) 时最优。因为我懒用 map 实现的 Hash 表,所以最后的复杂度会带 \(1\) 个 log。
代码:
P3846 [TJOI2007] 可爱的质数/【模板】BSGS
#include<bits/stdc++.h>
#define FOR(i,j,k) for(int i=(j);i<=(k);i++)
using namespace std;
int mod,a,b;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
inline int BSGS(int a,int b,int mod)
{
if(b==1) return 0;
int t=ceil(sqrt(mod));
map<int,int> mp;
int z=1;
for(int i=0;i<t;i++)
mp[1ll*b*z%mod]=i,z=1ll*z*a%mod;
int p=1;
for(int i=1;i<=t;i++)
{
p=1ll*z*p%mod;
if(mp.count(p)) return i*t-mp[p];
}
return -1;
}
int main()
{
mod=read(),a=read(),b=read();
int ans=BSGS(a,b,mod);
if(ans==-1) puts("no solution");
else printf("%d\n",ans);
return 0;
}
题目意思是给定 \(a,b,x_1,p,t\) 其中 \(p \in \text{Prime}\),\(0\le a,b,x_1,t<p\)。
定义 \(x_i=a\times x_{i-1}+b\),求最小的 \(n\) 使 \(x_n \equiv t \pmod p\)。
分析:大力化简。
我们得出一个很重要的结论: \(x_n=a^{n-1}\times x_1+b\sum\limits_{i=0}^{n-2}a^i\)
发现后面一项是等比数列求和。
设 \(S=\sum\limits_{i=0}^{n-2}a^i\),则 \(aS=\sum\limits_{i=1}^{n-1}a^i\),\((a-1)S=\sum\limits_{i=1}^{n-1}a^i-\sum\limits_{i=0}^{n-2}a_i=a^{n-1}-1\)。
那么 \(S=\dfrac{a^{n-1}-1}{a-1}\)。
带入后得到: \(x_n=a^{n-1}\times x_1 +b \dfrac{a^{n-1}-1}{a-1}=a^{n-1}\times x_1+a^{n-1}\dfrac{b}{a-1}-\dfrac{b}{a-1}=a^{n-1}(x_1+\dfrac{b}{a-1})-\dfrac{b}{a-1}\)
那么就有 \(x_n = a^{n-1}(x_1+\dfrac{b}{a-1})-\dfrac{b}{a-1}\equiv t \pmod p\)
即 \(a^{n-1}\equiv \dfrac{t+\frac{b}{a-1}}{x_1+\frac{b}{a-1}}\)。
直接 BSGS 即可。
有亿点点细节。
- 「1」当 \(x_1=t\) 时,\(n=1\)。
- 「2」当 \(a=0\) 时,\(x_n=0\)。
- 「3」当 \(a=1\) 时,等比数列求不了和, \(x_n=x_1+b(n-1)\equiv t \pmod p\), \(n=\dfrac{t-x_1+b}{b}\)。需要用 Bezout 定理。
N 次剩余
求解
其中 \(p\in \text{Prime}\)。(因为不会任意模数)
由于 \(p\) 为质数,则必存在一个原根 \(g\)。因此对于模 \(p\) 意义下的任意数 \(x(1\le x<p )\),都存在有一个数 \(i(0\le i <p-1)\) 满足 \(x=g^i\)。
方法一:
令 \(x=g^c\),则问题转化为 \((g^c)^a\equiv b \pmod p\),稍加转换即得 \((g^a)^c \equiv b\pmod p\)。这不就是我们的 BSGS 所干的事情吗?
可以 \(O(\sqrt{p})\) 求出一个特解 \(x_0 \equiv g^c \pmod p\)。
方法二:
令 \(x=g^c\),设 \(b=g^t\),于是有 \(g^{ac}\equiv g^t\pmod p\)。由阶的性质的 \(ac\equiv t \pmod {\varphi(p)}\)。其中 \(t\) 可以在 \(O(\sqrt{q})\) 内求出。于是就转化成了 exgcd 所做的事情。这样可以求出一个特解 \(c_0\),其通解为 \(c_0+k \dfrac{\varphi(p)}{\gcd(a,\varphi(p))}\),其中 \(k\) 是整数。可以用 vector 记录一下,用 Hash 表判重。
exBSGS
同样是求解
不过此时 \(a,p\) 不一定互质。我们可以想办法让她们互质。
具体地,设 \(d_1=\gcd(a,p)\)。若 \(d_1 \nmid b\),方程无解。否则将方程同时除以 \(d_1\),得:
若 \(a\) 和 \(\frac{p}{d_1}\) 仍不互质就继续重复上面的步骤,直到 \(\displaystyle \gcd\left(a,\frac{p}{\prod _{i=1}^{k} d_i}\right )\)。
记 \(D=\prod \limits_{i=1}^k d_i\),原方程被化为了:
此时 \(\gcd \left( \dfrac{a^k}{D},p\right)=1\),故 \(\dfrac{a^k}{D}\) 存在逆元,可以丢到式子右边。
这就是一个平凡的 BSGS 了。求解出 \(x-k\) 再加上 \(k\) 就是原方程的解。
有可能存在 \(x\le k\) 的情况。我们在消去因子前先 \(O(k)\) 枚举一下即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a,b,p;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1,y=0;
return a;
}
int gcd=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return gcd;
}
inline int exBSGS(int a,int b,int mod)
{
b%=mod;
if(b==1||mod==1) return 0;
int g=0,val=1;
while(true)
{
int d=gcd(a,mod);
if(d==1) break;
if(b%d) return -1;
b/=d,mod/=d,val=val*a/d%mod;
g++;
if(b==val) return g;
}
int x,y;
exgcd(val,mod,x,y);
x=(x%mod+mod)%mod;
b=b*x%mod,a%=mod;
map<int,int>mp;
int t=ceil(sqrt(mod));
int z=1;
for(int i=0;i<t;i++)
mp[b*z%mod]=i,z=z*a%mod;
int p=1;
for(int i=1;i<=t;i++)
{
p=p*z%mod;
if(mp.count(p)) return i*t-mp[p]+g;
}
return -1;
}
signed main()
{
a=read(),p=read(),b=read();
while(a||b||p)
{
int ans=exBSGS(a,b,p);
if(ans==-1) puts("No Solution");
else printf("%lld\n",ans);
a=read(),p=read(),b=read();
}
return 0;
}
Lucas
内容:
设 \(p\in \text{Prime}\),\(a,b\in \mathbb{N}^*\)。并且 \(a=\sum\limits _{i=0}^k m_ip^i,b=\sum\limits_{i=0}^{k}n_ip_i\)。
则有 \(C_b^a \equiv \prod \limits_{i=0}^k C_{m_i}^{n_i} \pmod p\)。
注意:若 \(n_i>m_i\),\(C_{m_i}^{n_i}=0\)。
然而我们一般使用的以下的这个式子:
证明:
(以下运算默认在模 \(p\) 意义下进行)
先证一个引理:
\((a+b)^p \equiv a^p+b^p \pmod p\)
我们考虑二项式展开,除了第一项和最后一项,其他项都含有 \(p\),故都被模没了。只剩下 \(a^p\) 和 \(b^p\)。
我们设 \(a=\lfloor \frac{a}{p}\rfloor \times p +a\bmod p\),\(a'=\lfloor \frac{a}{p}\rfloor\)。
则有:
\((1+x)^a=(1+x)^{\lfloor \frac{a}{p}\rfloor \times p +a\bmod p}=(1+x)^{a'\times p+a\bmod p}=(1+x)^{a'p}(1+x)^{a \bmod p}\)。
因为 \(a \bmod p=m_0\),所以 \((1+x)^{a'p}(1+x)^{a \bmod p}=((1+x)^p)^{a'}(1+x)^{m_0}=(1+x^p)^{a'}(1+x)^{m_0}\)。
再设 \(a'=\lfloor \frac{a'}{p}\rfloor \times p +a'\bmod p\),\(a''=\lfloor \frac{a'}{p}\rfloor\)。重复上述推导,得: \((1+{x^p}^2)^{a''}(1+x^p)^{m_1}\)。
就这样一直推下去直到
对左右两边分别使用二项式定理求 \(x^b\)。右边的每一项为 \(b\) 在 \(p\) 进制下对应的每一个数。
同除 \(x^b\) 即得。
当然也可以写成:(这不就是求一个数在 \(p\) 进制下的表示的过程吗)
exLucas
跟 Lucas 并没有关系的说。
前置芝士
- CRT
- exgcd
- 组合数
和 Lucas 求解的是一类问题,不过 exLucas 不要求模数为质数。
由于 \(p \not \in \text{Prime}\),考虑对其质因数分解
分解以后,我们只要求出 \(C_m^n\bmod p_i^{a_i}\) 的值,就可以用 CRT 合并出最终答案。
下面来考虑 \(C_m^n \bmod p^{a}\),我们都知道 \(C_m^n=\dfrac{m!}{n!\times(m-n)!}\)。但是此时 \(p^{a}\) 不一定与 \(n!,(m-n)!\) 互质,这样就没法求逆元了。我们考虑对于将这些阶乘中的 \(p_i\) 提出来,就变成了
其中 \(\dfrac{n!}{p^y}\) 和 \(\dfrac{(m-n)!}{p^z}\) 和 \(p^a\) 互质,可以直接求逆元。
下面我们来考虑计算形如 \(\dfrac{n!}{p^x}\bmod p^a\) 的式子。
先看 \(n! \bmod p^a\)。
举个例子: \(n=22,p=3,a=2\)。(网上举得基本上都是这个例子)
\(22!=1\times 2\times 3\times 4\times 5\times 6\times 7\times 8\times 9\times 10\times 11\times 12\times 13\times 14\times 15\times 16\times 17\times 18\times 19\times 20\times 21\times 22\)
把所有 \(p\) 的倍数提出来,得到:
还是那个例子:
\(22!=3^7\times \begin{matrix}\underbrace{(1\times 2\times 3\times 4\times 5\times 6\times 7)}\\\text{这些就是原先 3 的倍数}\end{matrix}\times(1×2×4×5×7×8×10×11×13×14×16×17×19×20×22)\)
因为 \(x\equiv x+p^a \pmod {p^a}\),所以我们发现最后一部分是循环的。
具体到例子里:\(1×2×4×5×7×8≡10×11×13×14×16×17 \pmod {3^2}\)
我们先暴力搞一个循环,然后快速幂计算其 \(\lfloor \frac n{p^a}\rfloor\) 幂。还剩下不能构成循环的最后几项,暴力乘一下。
这样三部分的乘积就是 \(n!\),最终还要除以一个 \(p^x\)。第一部分被约掉,不用管了。第二部分可以递归计算,过程中自然把 \(p\) 因子除去,故而最终答案就是第二部分递归后的结果与第三部分的乘积。
然后就可以计算了。
最后 CRT 合并即可。
狄利克雷卷积 Dirichlet Product
莫比乌斯反演
类欧几里得
\(\mathfrak{To}\) \(\mathfrak{Be}\) \(\mathfrak{Continued...}\)

浙公网安备 33010602011771号