数论笔记
-
本笔记结合徐骁扬学长的讲课和CM数学课
-
题单:CM数学课题单
注:勾选框表示题目
因数相关
结论
-
\(1\sim n\)的所有数的因数个数一共有\(O(n\log n)\),即\(\sum\limits_{i=1}^nd(i)=O(n\log n)\)
证明:
- \(\sum\limits_{i=1}^nd(i)=\sum\limits_{i=1}^n\sum\limits_{j\mid i}1=\sum\limits_{j=1}^n\sum\limits_{j\mid i\land 1\leq i\leq n}1=\sum\limits_{j=1}^n\lfloor\frac{n}{j}\rfloor\leq\sum\limits_{j=1}^n\frac{n}{j}=n\ln n\)
-
质数定理:\(1\sim n\)中质数个数为\(O(\frac{n}{\log n})\)
-
伯特兰-切比雪夫定理:\(n\geq 1\),\(n\sim 2n\)中至少有一个素数
-
直角三角形边长通式:\(a=w\cdot2uv,b=w\cdot(u^2-v^2),c=w\cdot(u^2+v^2)\),其中\(u,v,w\in\mathbb{Z^+}\)
题目
-
-
问题转化:找到\(x\)使得\(a_1,a_2,\cdots,a_n\)中至少有2个数是x的倍数
-
做法:
预处理\(1\sim10^6\)数的所有因数,扫过每一个\(a_i\)(可以去重以保证复杂度),把
cnt[a_i的一个因数]++,找到最大的\(x\)使cnt[x]\(\geq2\)。
-
-
-
观察:记\(\gcd(a_i+y,a_2+y,\cdots,a_n+y)=g_y\),则\(g_y\mid(a_i-a_j),1\leq i,j\leq n\)
所以,答案最大为\(g=\gcd\limits_{1\leq i,j\leq n\land i\neq j}(a_i-a_j)\)。
想要答案达到最大,发现\(a_i\equiv t\pmod g,1\leq i\leq n\),则让所有数加上\(-t\bmod g\)即可
快速计算\(g\):直接算\(g=\gcd\limits_{1\leq i\leq n-1}(a_{i+1}-a_i)\)
-
最大公约数相关
GCD
常用公式
-
\(\gcd(a,b)=\gcd(a,a+b)=\gcd(a,b-a)=\gcd(a,b\bmod a)=\gcd(b,a\bmod b)\)
-
\(\gcd(ab,ac)=a\cdot \gcd(b,c)\)
-
\(\gcd(a,b)\cdot\mathrm{lcm}(a,b)=a\cdot b\)
结论
- 若\(\gcd(a_1,a_2,\cdots,a_n)=g\),则\(\{a_1,a_2,\cdots,a_n\}\)的公因子等价于\(g\)的因子
辗转相除法
- 有式子\(\gcd(a,b)=\gcd(b,a\mod b)\),直到\(b=0\)时\(\gcd=a\)
实现
Type gcd(Type a,Type b){
return (y==0)?x:gcd(y,x%y);
}
-
复杂度分析:
发现,每递归一层\(\mathrm{l_2}a+\mathrm{l_2}b\)严格变小,于是复杂度是\(O(\log n)\)(规定\(\mathrm{l_2}\)表示一个数的二进制位数)
证明:
- \(\mathrm{l_2}a=\mathrm{l_2}b\),则两个数的二进制的第一位都为1,做一次后\(a\bmod b\)的二进制为至少少1
- \(\mathrm{l_2}a>\mathrm{l_2}b\),则\(a\bmod b\)一定比a小。
裴蜀定理
- 描述1:对于不定方程\(ax+by=c\),有整数解当且仅当\(\gcd(a,b)\mid c\)
- 描述2:\(a,b\)是不全为0的整数,则\(\exists x,y\),使\(ax+by=\gcd(a,b)\)
- 证明:按exGCD的方法递归构造即可
拓展
-
若\(\gcd(a_1,a_2,\cdots,a_n)=1\),则每个数\(N\)都可以表示为\(\{a_i\}\)的线性组合。
-
加强形式:若\(\gcd(a_1,a_2,\cdots,a_n)=g\),则每\(g\)的倍数\(N\)都可以表示为\(\{a_i\}\)的线性组合。
-
证明,归纳法:
-
\(n=1\)时,显然成立
-
\(n=2\)时,是裴蜀定理
-
\(n>2\)时,取\(b=\gcd(a_1,a_2,\cdots,a_{n-1})\),则\(g=\gcd(b,g_n)\)
根据裴蜀定理\(g=bx+a_ny\),则\(g\)的倍数都可以被表示出。
-
-
-
非负版本:充分大的正数,可以表示为\({a_i}\)的非负线性组合;其界可有同余最短路求出(?)。
exGCD
做法
对于方程\(ax+by=\gcd(a,b)\),
根据\(\gcd(a,b)=\gcd(b,a\mod b)\)写出同形式方程\(bx'+(a\mod b)y'=\gcd(b,a\mod b)\)
所以有:\(ax+by=bx'+(a-b*\lfloor\frac{a}{b}\rfloor)y'\)
化简:\(a(x-y')+b(y-x'+\lfloor\frac{a}{b}\rfloor*y')=0\)
其中一组可行解:\(\begin{cases} x=y'\\ y=x'-\lfloor\frac{a}{b}\rfloor*y' \end{cases}\)
可以递归的做,直到\(b=0\)时,\(a_tx_t+b_ty_t=\gcd(a_t,b_t)=a_t\)
此时的解:\(\begin{cases} x_t=1\\ y_t=任意值 \end{cases}\)
-
注意:当\(a,b\)有一个时负数时,不应该取\(\lfloor\frac{a}{b}\rfloor\),而是\(\lceil\frac{a}{b}\rceil\),即
c++自带的向0取整//验证程序 int a=1213121321,b=3123; for(int i=0;i<=1;i++){ for(int j=0;j<=1;j++){ int aa=a*(i==0?1:-1),bb=b*(j==0?1:-1); printf("%d%%%d=%d\n",aa,bb,aa%bb); printf("%d-[%d]*%d=%d\n",aa,aa/bb,bb,aa-aa/bb*bb); printf("%d-d%dd*%d=%d\n",aa,(int)floor(1.0*aa/bb),bb,aa-((int)floor(1.0*aa/bb))*bb); printf("%d-u%du*%d=%d\n",aa,(int)ceil(1.0*aa/bb),bb,aa-((int)ceil(1.0*aa/bb))*bb); printf("--------------\n"); } } -
注:用exgcd求出的解一定有\(|x|\leq b,|y|\leq a\)
实现
-
递归版
void exgcd(long long a,long long b,long long &x,long long &y){ if(b==0){ x=1,y=0; return ; } exgcd(b,a%b,y,x); y-=a/b*x; }
不定方程
求解\(ax\equiv 1(\mod b)\),相当于求\(ax+by=1\)的解,使用exgcd
- 注意:根据裴蜀定理,有解时\(\gcd(a,b)=1\),但题目保证有解,即\(a,b\)一定互质
求出特解\((x_0,y_0)\)后,任意解可以为\((x_0+k\cdot b,y_0-k\cdot a)\),其中\(k\in \mathbb{Z}\)
- 推导1:
-
根据裴蜀定理判无解
-
先求出\(ax+by=\gcd(a,b)\)的一组解\((x_g,y_g)\),然后同时乘以\(\frac{c}{\gcd(a,b)}\)得到原方程的一组解\((x_0,y_0)=(x_g\cdot \frac{c}{\gcd(a,b)},y_g\cdot \frac{c}{\gcd(a,b)})\)
-
若改变解\((x_0,y_0)\to (x_0+d_x,y_0-d_y)\)也使方程成立,即\(a(x_g\cdot \frac{c}{\gcd(a,b)}+d_x)+b(y_g\cdot \frac{c}{\gcd(a,b)}-d_y)=c\)
化简:\(x_g\cdot \frac{b\cdot c}{\gcd(a,b)}+a\cdot d_x+y_g\cdot \frac{a\cdot c}{\gcd(a,b)}-b\cdot d_y=c\)
有:\(a\cdot d_x=b\cdot d_y\)
要使每次的增减量最小且为整数,则\(d_{x_{min}}=\frac{b}{\gcd(a,b)},d_{y_{min}}=\frac{a}{\gcd(a,b)}\)
-
然后据此计算出\(x\)的最小正整数值及对应的\(y\),和\(y\)的最小正整数值及对应的\(x\),即可
- 推导2:
- 判无解后,如果\(\gcd(a,b)>1\),则将方程两边除掉\(\gcd(a,b)\),方程变为\(\frac{a}{\gcd(a,b)}x+\frac{b}{\gcd(a,b)}y=\frac{c}{\gcd(a,b)}\),记为\(a'x+b'y=c'\)
- 用exGCD找到\(a'x+b'y=1\)的一组特解\((x',y')\),则原解为\(a'(c‘x')+b'(c’y')=c'\),记为\(a'x_0+b'y_0=c’\)
- 此时方程的通解为\(\begin{cases}
x=x_0+b't\\
y=y_0-a't
\end{cases}\),其中\(t\in\mathbb{Z}\)
- 验证其是解:\(a'(x_0+b't)+b'(y_0-a't)=ax_0+by_0=c'\)
- 证明未漏掉解:
- 设\(a'x+b'y=a'x_0+b'y_0\)
- 移项\(a'(x-x_0)=b'(y_0-y)\)
- 由于\(a\perp b\),则\(b\mid x-x_0,a\mid y_0-y\),即\(x\)和\(x_0\)的差是\(b\)的倍数,\(y\)和\(y_0\)的差是\(a\)的倍数,通解形式正确
- 带回\(a,b,c\),得\(\begin{cases} x=\frac{c}{\gcd(a,b)}x'+\frac{b}{\gcd(a,b)}t\\ y=\frac{c}{\gcd(a,b)}y'-\frac{a}{\gcd(a,b)}t \end{cases}\)
-
描述:有两个正整数\(a,b\)且\(a\perp b\),要找到最小的\(N\),使得\(ax+by\)不能表示出\(N\)(\(a,b\geq0\))
-
如果\(x,y\)无限制,根据裴蜀定理,任何整数都一定可以被表示。
-
答案:\(N=ab-a-b=(a-1)(b-1)-1\)
- 证明:
-
\(N\)无法被表示
假设\(N\)可以被表示
记\(N=ax+by\),其中\(a,b\geq0\),则\(ab-a-b=ax+by\),则\(ab=a(x+1)+b(y+1)\)
由于\(a\perp b\),得\(b\mid x+1,a\mid y+1\),所以\(x+1\geq b,y+1\geq a\),
因此\(a(x+1)+b(y+1)\geq2ab\),矛盾!
-
\(>N\)的数都可以被表示
记\(n\)是\(>N\)的一个数,先找到一组整数解\(ax_0+by_0=n\),满足\(y_0\in[0,a-1]\),
则\(ax_0=n-by_0>ab-a-b-by_0\geq ab-a-b-b(a-1)=-a\),所以得到\(x_0>-1\),即\(x_0\geq0\),得证。
-
相关结论
-
\(n\in[0,N]\)时,\(n\)和\(N-n\)恰好有一个可以被表示。
-
证明:
-
不可能两个都被表示,否则\(N=n+(N-n)\)就可以被表示了
-
设\(n\)不可被表示,求证\(N-n\)可以被表示
设\(n=ax_0+by_0\),若\(0\leq y_0\leq a-1\),则有\(x_0<0\)
然后有\(N-n=ab-a-b-ax_0-by_0=a(-x_0-1)+b(a-1-y_0)\),其中\(a-1-y0\geq0,-x0-1>1\),得证。
-
-
-
多元不定方程
-
转化:\(a_1x_1+a_2x_2+\cdots+a_nx_n=p(-k)+b\),记\(a_{n+1}=p,x_n+1=k\),则\(a_1x_1+a_2x_2+\cdots+a_{n+1}x_{n+1}=b\)
-
根据裴蜀定理加强版,有解时有\(\gcd(a_1,a_2,\cdots,a_{n+1})\mid b\)
-
于是先把原式除掉\(\gcd(a_1,a_2,\cdots,a_{n+1})\mid b\),记作\(a_1'x_1+a_2'x_2+\cdots+a_{n+1}'x_{n+1}=b'\)
-
递归的把它做成一个\(n=2\)的情况:
记\(a_1'x_1+a_2'x_2+\cdots+a_n'x_n=\gcd(a_1,a_2,\cdots,a_n)X\),则须求解\(\gcd(a_1,a_2,\cdots,a_n)X+a_{n+1}x_{n+1}=b\),然后递归即可。
同余相关
同余类与缩同余类
- 模\(m\)的同余类:\(\mathbb{Z}_m=\{\overline0,\overline1,\cdots,\overline{m-1}\}\),
其是一个群 - 模\(m\)的缩同余类:\(\mathbb{Z}_m^*=\{\overline x\mid x<x<m,\gcd(x,m)=1\}\),
其关于乘法封闭
模意义下的乘法逆元
-
\(a\in\mathbb{Z}_m^*\space(\gcd(a,m)=1)\),则\(\exists b\in\mathbb{Z}_m^*\),\(a\cdot b=1\pmod m\)
-
证明:转换成exGCD即可
-
以下的\(p\)表示模数
-
\(a\)在\(\mod p\)意义下的逆元存在,当且仅当\(p\perp a\)
法1:费马小定理求逆元
-
定理:\(a^{p-1}\equiv 1(\mod p)\),其中\(p\)为质数,\(p\perp a\)
那么\(a^{-1}\equiv a^{p-2}(\mod p)\)
-
注意:仅限于模数为质数的时候
-
【补充】欧拉定理:\(a^{\varphi(p)}\equiv 1(\mod p)\),只需要满足\(p\perp a\)
long long inverse(long long x,long long MOD){
return quickpow(x,MOD-2ll,MOD);
}
法2:exGCD求逆元
- 解同余方程\(a\cdot x\equiv 1(\mod p)\),其中\(x=a^{-1}\),只需要满足\(\gcd(a,p)=1\)
long long inverse(long long a,long long MOD){
long long res,_y;
exgcd(a,MOD,res,_y);
while(res<0)res+=MOD;
while(res>=MOD)res-=MOD;
return res;
}
法3:阶乘求逆元
- 此方法为\(O(n+logV)\)求出前\(n\)个数的逆元,并且需要模数为质数
- 求出\(fac[i]=i!\),然后用前两种方法求出\(fac[n]\)的逆元\(invfac[n]\)
- 倒序递推:\(invfac[i]=invfac[i+1]*(i+1)\),\(inv[i+1]=invfac[i+1]*fac[i]\)
long long inv[N],invfac[N],fac[N];
void inverse_n(long long n,long long MOD){
fac[0]=1;
for(long long i=1;i<=n;i++){
fac[i]=((__int128)1)*fac[i-1]*i%MOD;
}
invfac[n]=inverse(fac[n],MOD);//建议用exGCD
for(long long i=n-1;i>=0;i--){
invfac[i]=((__int128)1)*invfac[i+1]*(i+1)%MOD;
inv[i+1]=((__int128)1)*invfac[i+1]*fac[i]%MOD;
}
return ;
}
法4:线性递推求逆元
-
需要模数为质数
-
边界:\(1^{-1}\equiv 1(\mod p)\)
-
令\(p=i\cdot s+t\),则\(s=\lfloor\frac{p}{i}\rfloor,t=p\mod i\)
由于\(p=i\cdot s+t\equiv0(\mod p)\)
两边同时乘以\(i^{-1}t^{-1}\),并移项得:\(i^{-1}\equiv -s\cdot t^{-1}(\mod p)\)
因此得到递推式:\(i^{-1}\equiv \lfloor\frac{p}{i}\rfloor\cdot \Big(p-(p \mod i)^{-1}\Big)(\mod p)\)(用\(p-\dots\)防止负数出现)
long long inv[N];
void inverse_n(long long SIZE,long long MOD){
inv[1]=1;
for(int i=2;i<=SIZE;i++){
inv[i]=((__int128)1)*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
}
求任意n个整数的逆元
- 类似阶乘求逆元,\(O(n+logV)\)求出任意n个整数的逆元
- 求出数的前缀乘积\(sum[i]=\prod\limits_{j=1}^ival[i]\),然后用前两种方法求出\(sum[n]\)的逆元\(invsum[n]\)
- 倒序递推:\(invsum[i]=invsum[i+1]*(i+1)\),\(inv[i+1]=invsum[i+1]*sum[i]\)
-
考虑\(K<N\)的情况,否则\(K=N*d+K'\),让序列中所有元素加上\(d\)即可。
现在需要的到一个其中有\(K\)个1,其他是0的序列满足条件。
-
记\(L=K^{-1}\pmod N\),则把\(S_0,S_L,S_{2l},\cdots,S_{(K-1)L}\)的位置设为0(第0位表示第\(N\)位),可以发现这些位置互不相同(\(K\perp N\))。
-
原来的操作让\(S_0\)变为0,让\(S_1(S_{KL})\)变为1,满足循环同构的条件
-
据金恺本人说是CTSC刚出的一道题目,但是没找到。讲于CM1-1
中国剩余定理CRT
-
找到同余方程组\(x\equiv a_i(\mod p_i)\)的解,满足所有模数\(p_i\)互质
-
一个思路是,从零开始加,加的数不会影响其他同余方程的结果,只会让某一个同余方程的结果加1
-
可以发现\(d_i=\prod\limits_{j=1}^n[j\not=i]p_j\),其中\(d_i\not\equiv0(\mod p_i)\land d_i\equiv0(\mod p_j,j\not=i)\)
-
因此,需要只让一个同余方程结果加1可以加\(d_i\cdot\Big(d_i^{-1}(\mod p_i)\Big)\)
-
最终答案为\(\sum\limits_{i=1}^na_i\cdot d_i\cdot\Big(d_i^{-1}(\mod p_i)\Big)\)
-
答案任意\(\pm k\cdot\mathop{\text{lcm}}\limits_{i=1}^np_i\)也满足条件
exCRT
-
对于\(p_i\)不互质的情况,考虑两两合并同余方程
-
对于两个同余方程\(\begin{cases}x\equiv a_i(\mod p_i)\\x\equiv a_j(\mod p_j)\end{cases}\),可以写作\(\begin{cases}x+k_i\cdot p_i=a_i\\x+k_j\cdot p_j=a_j\end{cases}\),消去\(x\)得\(k_i\cdot p_i-k_j\cdot p_j=a_i-a_j\)
-
用exGCD可以求出\(k_i\)或\(k_j\)即可求出共同的解\(x\equiv h(\mod \text{lcm}(p_i,p_j))\)
补充
-
若同余方程有系数,如\(b_ix\equiv a_i(\mod p_i)\),我们把它写作不定方程\(b_ix+p_ik=a_i\)。
-
根据裴蜀定理:如果\(\gcd(b_i,p_i)\nmid a_i\),则无解;
否则,先用exGCD解出\(b_ix+p_ik=gcd(b_i,p_i)\)的一组特解\(x_0\),同二元一次不定方程的解法,通解\(x=x_0\cdot \frac{a_i}{\gcd(b_i,p_i)}+any\cdot\frac{p_i}{\gcd(b_i,p_i)}\)。
-
于是就得到了系数为\(1\)的同余方程:\(x=x_0\cdot \frac{a_i}{\gcd(b_i,p_i)}\pmod{\frac{p_i}{\gcd(b_i,p_i)}}\),然后用exCRT合并。
BSGS
-
描述:求解\(a^x\equiv b\pmod p\)的最小解,其中\(a\perp p\),也就是模意义下的对数(离散对数)。
-
根据欧拉定理,有解则解一定\(\leq \varphi(p)\),于是把式子写作\(a^{qB+r}\equiv b\pmod p\),其中\(B=\lceil\sqrt{\varphi(p)}\rceil\),\(r<B\)。
由于\(a\perp p\),式子可以改为\((a^{B})^{q}\equiv b\cdot (a^{-1})^{r}\pmod p\),处理出同余式两边的值,查询是否有相等的,即可找到答案。
-
注意:查询相等时,用哈希表把\((a^{-1})^r\)做键,\(r\)做值,此时键会重复,要取最小的一个,要特判!!
hack:
5598755 2642091 857926
exBSGS
-
要求离散对数,但是不满足互质条件,无法求逆元。
-
对于原方程\(a^x\equiv b\pmod p\),考虑构造\(a\perp p\)的情况。
求\(g=\gcd(a,p)\),如果\(g\nmid b\),则说明无解;
否则,两边同时除以\(g\):\(a^{x-1}\cdot\frac{a}{g}\equiv\frac{b}{g}\pmod{\frac{p}{g}}\)。
然后,现在\(\frac{a}{g}\perp \frac{p}{g}\)了,把它挪到右边:\(a^{x-1}\equiv\frac{b}{g}\cdot(\frac{a}{g})^{-1}\pmod{\frac{p}{g}}\),注意:要在最后求\(\prod \frac{a}{g_i}\)逆元;
但是\(a\)和\(\frac{p}{g}\)不一定互质,递归继续做。
-
考虑到\(g\geq2\),所以每次至少让\(p\)变为一半,至多做\(O(\log_2p)\)次,做完后再用普通BSGS做即可。
注意:不能保证答案\(>\log_2p\),所以还要枚举\(i=0\sim\log_2p\),验证\(a^i\bmod p\)是否为\(b\)。
积性函数相关
求解一般积性函数前n项函数值方法
积性函数
- 一个积性函数\(f(x)\)满足:\(f(ab)=f(a)\cdot f(b)\)其中\(a\perp b\)(\(a,b\)互质)
求法(线性筛)
-
需要知道\(f(1)\)的值
-
质数求法:对于一个质数\(p\),需要知道如何求\(f(p)\)的值
-
递推求法:对于\(p^k\),其中p是质数,需要知道如何用\(f(p^k)\)和\(f(p^{k-1})\)的递推关系求值
-
在筛法过程中,记录数\(x\)的最小质因子\(p\)在\(x\)中的次方值\(val[x]=p^k\)
-
当\(x\)是质数时,用质数求法
-
枚举质数\(p_i\)时
-
如果\(p_i\perp x\),则根据积性函数性质\(f(x\cdot p_i)=f(x)\cdot f(p_i)\);此时\(val[x\cdot p_i]=p_i\)
-
如果\(p_i\mid x\),此时\(val[x*p_i]=p_i*val[x]\)
-
若\(x=p_i^k\),则用递推求法从\(f(x)\)(\(f(p_i^k)\))推到\(f(x*p_i)\)(\(f(p_i^{k+1})\))
-
否则\(f(x*p_i)=f(\frac{x}{val[x]})*f(val[x]*p_i)\)(保证互质才能使用积性函数的性质)
-
-
- 可能要预处理一些值
求\(\sigma_d(x)\)的代码:
long long d,f[N],val[N];//f:\sigma_d
bitset<N>book;
vector<pair<int,long long>>pr;
void euler(int n){
book[0]=book[1]=1;
f[0]=0,f[1]=1;
for(int i=2;i<=n;i++){
if(!book[i]){
pr.emplace_back(i,quickpow(i,d));
f[i]=quickpow(i,d)+1;
val[i]=i;
}
for(auto v:pr){
if(1ll*i*v.first>n)break;
book[i*v.first]=1;
if(i%v.first==0){
val[i*v.first]=val[i]*v.first;
if(i==val[i])
f[i*v.first]=f[i]*v.second+1;
else
f[i*v.first]=f[i/val[i]]*f[val[i]*v.first];
break;
}
else{
val[i*v.first]=v.first;
f[i*v.first]=f[i]*f[v.first];
}
}
}
}
- lucas性质\(C(m,n)\mod 2\equiv [(n\&m)=1]\)??
浙公网安备 33010602011771号