数论 工具 线性筛
由于做莫反题需要大量的基础函数知识,于是有了这篇文章将我做到的函数都记录下来。
持续施工中。
约数和函数 \(\sigma\)
定义:\(\sigma(x)=\sum_{d|x} d\)。
证其为积性函数:
设 \(x=\prod p_i^{a_i}\),设 \(d\) 为 \(x\) 的质因数个数,那么发现:
我们发现当 \(d=1\) 时,\(\sigma(x)=\sum_{i=0}^{a_1} p_1^i\),即上述式子可以转化为:
推广可得:
证毕。
接下来考虑如何线性筛。考虑我们当前的数 \(i\),令其最小的质因子为 \(p\)。由积性函数可知,我们需要先使两个数 \(a,b\) 互质,再由 \(\sigma(a\times b)=\sigma(a)\sigma(b)\) 转移。那么我们若想从 \(\sigma(i)\) 转移至 \(\sigma(i\times p)\),需要先将 \(i\) 中所有的质因子 \(p\) 除掉,转移式子即为 \(\sigma(i\times p)=\sigma(\frac{i}{p^{a_1}})\sigma(p^{a_1+1})\)。用 \(low_i\) 维护 \(\sigma(p^{a_1})\),那么 \(low\) 的转移有 \(low_{i\times p}=low_{i}\times p+1\),此时 \(\sigma\) 的转移有 \(\sigma(i\times p)=\frac{\sigma(i)}{low_i}\times low_{i\times p}\)。
实现中,当出现 \(i \mod p_j=0\) 的情况就用上述方法转移,否则 \(\sigma_{i\times p_j}\) 直接用积性函数性质求,\(low_{i\times p_j}\) 的值等于 \(\sigma(p_j)\),因为如果此时 \(i\) 中有比 \(p_j\) 更小的质因子的话,早在前面就会被筛出来然后 break 掉。
因为 \(\sigma\) 跟 \(o\) 挺像,所以在代码中 \(o_i\) 表示 \(\sigma(i)\)。
int pri[N],tot,o[N],low[N];
bool vis[N];
void Wprepare()
{
o[1]=1;
for(int i=2;i<=N;i++)
{
if(!vis[i]) pri[++tot]=i,o[i]=low[i]=i+1;
for(int j=1;j<=tot;j++)
{
if(i*pri[j]>N) break;
vis[i*pri[j]]=1;
if(i%pri[j]==0)
{
low[i*pri[j]]=low[i]*pri[j]+1;
o[i*pri[j]]=o[i]/low[i]*low[i*pri[j]];
break;
}
low[i*pri[j]]=pri[j]+1;
o[i*pri[j]]=o[i]*o[pri[j]];
}
}
}
例题是 [SDOI2014]数表,莫反部分不难,难点在理解如何筛约数和以及动态维护某个函数前缀和,练习 \(\sigma\) 函数的好题。