学习笔记:用线性筛算不太常见的函数
做 ABC 的时候 D 题是板子然而不会,就找到学了一下(考试作弊.jpg
线性筛求一个数 \(a\) 的因子个数 (\(\sigma(a)\))
容易发现当 \(a\in P\) 时,\(\sigma(a)=2\),因为只有 \(1,a\)。
按照线性筛的三板斧, \(a\not\in P\) 时,要分两种情况。
\(1.\) \(p\not|\;a\) 那么两数的因子两两组合一定不会重复,即
\(\sigma(a×p)=\sigma(a)×\sigma(p)\)。
\(2.\) \(p|a\)
考虑:
那么:
其中 \(p_{now}=p\),\(p,k\) 下标一一对应。
所以维护一个 \(e\) 数组代表一个数的最小质因子出现的次数,更新比较显然。
\(Code:\)
void get(int n)
{
t[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i]) pri[++cnt]=i,t[i]=2,e[i]=1;
for(int j=1;j<=cnt&&1ll*pri[j]*i<=(ll)n;j++)
{
vis[i*pri[j]]=1;
if(i%pri[j]==0){t[i*pri[j]]=t[i]/(e[i]+1)*(e[i]+2),e[i*pri[j]]=e[i]+1;break;}
else t[i*pri[j]]=t[i]*2,e[i*pri[j]]=1;
}
}
return;
}
线性筛求一个数 \(a\) 的因子和
为了方便,记:
即为这个数的约数和。
\(1.\) 当 \(a\in P\) 时,显然 \(\varepsilon(a)=1+a\)。
\(2.\) 当 \(a\not\in P, p\not|\;a\) 时,发现从前的因子还是 \(a×p\) 的因子,那么又多了哪些呢?
显然从前的因数 \(s_i×p\) 是 \(a×p\) 的因数,容易证明没有其他的了。
也就是说此时:
\(3.\) 当 \(a\not\in P, p|\;a\) 时,这时候如果用上述方法就有重复了...
因为原来的因子与此素数相乘有可能还是原来的因子,这样相加就有重复。
如果不算原来的就会有缺失,那么考虑缺失了哪些?
显然 \(a\) 中不能整除 \(p\) 的因子都会缺失,因为没有其他因子 \(×p\) 成为一个 “不能整除 \(p\) 的因子”。
那我们设 \(e_i\) 为 \(i\) 的因子中不能整除 \(i\) 的最小质因子的因子和。
这里有一个技巧,在线性筛判断整除的时候,如果 i%pri[j]==0
,这个 pri[j]
一定是 \(i\) 的最小质因子,因为他是第一个能整除的质数嘛。
容易得到,此时:
\(e\) 的更新也比较显然。
\(Code:\)
void get(int n)
{
t[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i]) pri[++cnt]=i,t[i]=i+1,e[i]=1;
for(int j=1;j<=cnt&&1ll*pri[j]*i<=1ll*n;j++)
{
vis[i*pri[j]]=1;
if(i%pri[j]==0){t[i*pri[j]]=t[i]*pri[j]+e[i];e[i*pri[j]]=e[i];break;}
else t[i*pri[j]]=t[i]*(pri[j]+1),e[i*pri[j]]=t[i];
}
}
return;
}
这个东西比较大,一般要开 long long
的。