数论
数论
对积性函数一套的知识之外的数论算法和经典问题进行整理。
质因数分解
记值域为 \(W\)。
预处理 \(O(W)\),单次分解 \(O(\log W)\)
线性筛预处理出值域内数的最小质因子即可。
预处理 \(O(\sqrt W)\),单次分解 \(O(\pi(\sqrt W)+\log W)\)
线性筛 \(\sqrt W\)。每次分解枚举 \(\sqrt W\) 内质数试除,只会剩至多一个超过 \(\sqrt W\) 的质因子。
单次分解期望复杂度 \(O(W^{\frac 1 4}\log^2 W)\)
Miller_rabbin
对 \(2^{32}\) 以内的数判素,使用 \(2,7,61\) 三个底数即可。
对 \(2^{64}\) 以内的数判素,使用 \(2,325,9375,28178,450775,9780504,1795265022\) 七个底数。
使用前 \(12\) 个素数作为底数可以处理 \(2^{78}\) 以内的判素。
注意特判底数。
Pollard_Rho
namespace PR{
inline ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
inline ll power(ll x,ll p,ll mod){
ll ans=1;
while(p){
if(p&1)ans=(lll)ans*x%mod;
x=(lll)x*x%mod;
p>>=1;
}
return ans;
}
inline bool mr(ll x,ll b){
ll k=x-1;
while(k){
ll cur=power(b,k,x);
if(cur!=1&&cur!=x-1)return false;
if((k&1)==1||cur==x-1)return true;
k>>=1;
}
return true;
}
const int coef[]={2,325,9375,28178,450775,9780504,1795265022};
inline bool isprime(ll x){
if(x==2||x==3||x==5||x==13||x==19||x==73||x==193||x==407521||x==299210837)return true;
for(int i=0;i<7;i++)if(!mr(x,coef[i]))return 0;
return 1;
}
inline ll f(ll x,ll c,ll n){return ((lll)x*x+c)%n;}
mt19937 rnd(time(0));
inline ll Pollard_Rho(ll x){
ll s=0,t=0,c=1ll*rnd()%(x-1)+1;
ll val=1;
for(int lim=1;;lim<<=1){
s=t,val=1;
for(int st=1;st<=lim;st++){
t=f(t,c,x);
val=(lll)val*abs(t-s)%x;
if((st%127)==0){
ll d=gcd(val,x);
if(d>1)return d;
}
}
ll d=gcd(val,x);
if(d>1)return d;
}
}
vec<ll> pr;
inline void fac(ll x){
if(x<2)return ;
if(isprime(x)){pr.eb(x);return ;}
ll p=x;
while(p>=x)p=Pollard_Rho(x);
fac(x/p),fac(p);
return ;
}
};
欧几里得算法
辗转相除法,太典了,不予展开。
int gcd(int x,int y){return (y==0)?x:gcd(y,x%y);}
扩展欧几里得算法(exgcd)
裴蜀定理:对于一个二元一次不定方程 \(ax+by=c\) 有解的充要条件是 \(\gcd(a,b)|c\)。
对于固定的 \(a,b\) 我们使用 exgcd 得到一组满足 \(ax+by=\gcd(a,b)\) 的解 \((x,y)\)。
算法思路是已知欧几里得算法迭代后的一组解,构造出当前的解。
int exgcd(int x,int y){
if(y==0){p=1;q=0;return x;}
int g=exgcd(y,x%y);ll tmp=p;
p=q;q=tmp-(x/y)*q;
return g;
}
一个有趣的结论是 exgcd 求得的一组 \((p,q)\) 是所有合法解中 \(|p|+|q|\) 最小的。
中国剩余定理(crt)
求解模意义下的线性同余方程组。
excrt
记我们已经合并出一个方程 \(x\equiv v\pmod M\),加入一个新的方程 \(x\equiv a\pmod m\)。
考虑 \(x=v+sM,x=a-tm\),转化成一个二元一次不定方程:\(sM+tm=x-v\)。
无解条件即是该方程无解的条件,否则使用 exgcd 构造 \(s,t\) 计算解 \(w\),即可得到合并出的新方程:\(x\equiv w\pmod{\operatorname{lcm}(M,m)}\)。
crt
对于同余方程组模数两两互质的情况,存在更简单的做法。
记我们需要解决的线性方程组形式为:\(x\equiv a_1\pmod{m_i}\)。
计算 \(c_i=\prod_{j\neq i} m_j\) 与 \(d_i\)(在模 \(m_i\) 意义下 \(c_i\) 的逆元)。
那么方程组在模 \(\prod m_i\) 意义下的唯一解为 \(\sum a_ic_id_i\)。
卢卡斯定理(Lucas)
使用 Lucas 定理解决小模数下的大组合数取值问题。
对于质数 \(p\),有:
一个常见的应用是组合数模 2,有值等价于二进制下 \(m\in n\)。
库默尔定理(Kummer)
对于质数 \(p\),组合数 \(\dbinom{n}{m}\) 中 \(p\) 的幂次 \(v_p(\dbinom n m)\) 为 \(p\) 进制下 \(n\) 减去 \(m\) 的借位次数。
稍加修改,可以变成 \(\dbinom{n+m}m\) 中 \(p\) 的幂次为 \(p\) 进制下 \(n\) 加上 \(m\) 的进位次数。
配合数位 DP 使用。
扩展卢卡斯(exLucas)
Hard!
大步小步算法(BSGS)
常用于解决离散对数问题,但该算法也可以用于特殊情况下图判环等问题。
考虑求解 \(a^x\equiv b\pmod p\),要求 \(\gcd(a,p)=1\)。
记 \(B=\lceil\sqrt{\varphi(p)}\rceil\),将 \(x\) 表示成 \(pB+q\),满足 \(1\leq p,q\leq B\),稍加变换,得到 \(a^{pB}\equiv a^{q}\pmod p\)。
先计算得 \(a^B\)(大步),将 \(a^{pB},p\in [1,B]\) 存入数据结构(哈希表/map),查询所有 \(a^q,q\in [1,B]\) 即可。
复杂度 \(O(\sqrt{\varphi(p)})\)。
扩展大步小步算法(exBSGS)
Hard!
二次剩余
下文只考虑 \(p\) 为奇素数的情形。
对于常数 \(a\) 求解方程:\(x^2\equiv a\pmod p\)。
定义勒让德(Legendre)符号 \(\left(\dfrac a p\right)=\begin{cases}1&p\nmid a,a\text{ 是模 } p \text{ 的二次剩余}\\-1&p\nmid a,a\text{ 不是模 } p \text{ 的二次剩余}\\0& p\mid a\end{cases}\)。
计算勒让德符号的方法是欧拉判别准则:\(\left(\dfrac a p\right)\equiv a^{(p-1)/2}\pmod p\)。
\(p\) 确定的情况下 \(\left(\dfrac {ab} p\right)=\left(\dfrac a p\right)\left(\dfrac b p\right)\),其为一个完全积性函数。
勒让德符号一个经典的性质是二次互反律:对于两个奇素数 \(p,q\),\(\left(\dfrac q p\right)=\left(\dfrac p q\right)(-1)^{(p-1)(q-1)/4}\)。
回到二次剩余的问题上,模 \(p\) 意义下,二次剩余的数量与二次非剩余的数量相同。证明可以考虑原根。
Cipolla 算法
求解 \(x^2\equiv a\pmod p\)。
找到一个 \(r\) 满足 \(r^2-a\) 为二次非剩余,那么 \(\pm(r+z)^{(p+1)/2}\bmod(z^2-(r^2-a))\) 为两个解。解的叙述进行了扩域操作。
由于二次非剩余的数量与二次剩余的数量相当,我们可以随若干个数使用欧拉判别准则判断是否是二次非剩余以找到一个满足条件的 \(r\)。
引理1:\(z^p=-z\)。提一个 \(z\) 出来剩余的部分由于 \(r^2-a\) 为二次非剩余可以化简。
引理2:\((A+B)^p\equiv A^p+B^p\)。二项式定理展开即可证明。
那么 \((r+z)^{p+1}\equiv (r^p+z^p)(r+z)\equiv (r-z)(r+z)\equiv r^2-z^2\equiv a\)。
整除分块
核心的结论是对于 \(i\in[1,n]\),本质不同的 \(\lfloor \dfrac n i\rfloor\) 只有 \(O(\sqrt n)\) 种,具体的数量是约 \(2\sqrt n\)。
这里放一些经典的复杂度分析:
- \(\sum_{i=1}^n\dfrac{n}{i}=O(n\ln n)\)
- \(\sum_{i=1}^{\sqrt n}\sqrt{\dfrac{n}{i}}=O(n^{3/4})\)
- \(\sum_{i=1}^{n}\sqrt{\dfrac n i}=O(n)\)
积性函数
块筛
称得到数论函数所有 \(\lfloor\dfrac{n}{i}\rfloor\) 位置的前缀和为块筛。
狄利克雷卷积
即对于两个数论函数 \(f,g\),\((f*g)(n)=\sum_{d|n}f(d)g(\dfrac n d)\)。
两个数论函数的卷积可以由定义式得到 \(O(n\ln n)\) 的做法。
对于积性函数卷数论函数,存在通用的 \(O(n\log\log n)\) 做法。
考虑将积性函数 \(f\) 拆成 \(f_{p_1}*f_{p_2}* \cdots\),其中 \(f_p\) 表示只保留 \(f\) 中 \(p\) 的次幂处的点值的积性函数,我们给数论函数卷上这些部分即可完成狄利克雷卷积。
对于一个质数 \(p\),我们可以在 \(\sum \dfrac{n}{p^i}=O(\dfrac n p)\) 的时间完成卷积,那么总时间复杂度是 \(O(\sum_p \dfrac n p)=O(n\log\log n)\)。
贝尔级数
对于积性函数 \(f\),定义其在质数 \(p\) 意义下的贝尔级数为 \(F_p(z)=\sum f(p^i)z^i\)。
即在质数 \(p\) 处观察这个积性函数。显然,这将狄利克雷卷积变成了普通的多项式卷积。
一些常见积性函数的贝尔级数如下,要用到的时候推一推也很方便:
- \(\epsilon\) :\(1\)
- \(I\):\(\dfrac{1}{1-z}\)
- \(id_k\):\(\dfrac{1}{1-p^kz}\)
- \(\mu=I^{-1}\):\(1-z\)
- \(\varphi\):\(\dfrac{1-z}{1-pz}\)
筛法
记带求积性函数为 \(f\)。
线性筛可以 \(O(n)\) 得到任意积性函数的前 \(n\) 项,好写好用。
杜教筛可以处理一些性质优越数论函数的块筛问题,一个优美的结论是只要我们知道函数 \(f,g\) 的块筛,可以使用杜教筛获得 \(f*g,f/g\) 的块筛。
具体的,我们需要构造一个函数 \(g\) 满足 \(g\) 的前缀和易求,且 \(f*g\) 的前缀和易求,可以结合贝尔级数考虑合理的辅助函数,其具体推导过程是:
一些经典的容易使用杜教筛解决的式子是:\(\mu,\varphi,\mu\cdot id_k,\varphi\cdot id_k\)。