做 ABC 的时候 D 题是板子然而不会,就找到学了一下(考试作弊.jpg
线性筛求一个数 (a) 的因子个数 ((sigma(a)))
容易发现当 (ain P) 时,(sigma(a)=2),因为只有 (1,a)。
按照线性筛的三板斧, (a otin P) 时,要分两种情况。
(1.) (p
ot|;a) 那么两数的因子两两组合一定不会重复,即
(sigma(a×p)=sigma(a)×sigma(p))。
(2.) (p|a)
考虑:
[a=prod p_i^{k_i}
]
[sigma(a)=prod(k_i+1)
]
那么:
[sigma(a*p)=(k_{now}+1+1)prodlimits_{p
ot=p_i}(k_i+1)
]
其中 (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) 的因子和
为了方便,记:
[varepsilon(a)=sumlimits_{d|a}d
]
即为这个数的约数和。
(1.) 当 (ain P) 时,显然 (varepsilon(a)=1+a)。
(2.) 当 (a otin P, p ot|;a) 时,发现从前的因子还是 (a×p) 的因子,那么又多了哪些呢?
显然从前的因数 (s_i×p) 是 (a×p) 的因数,容易证明没有其他的了。
也就是说此时:
[varepsilon(a×p)=varepsilon(a)+varepsilon(a)×p=varepsilon(a)(1+p)
]
(3.) 当 (a
otin P, p|;a) 时,这时候如果用上述方法就有重复了...
因为原来的因子与此素数相乘有可能还是原来的因子,这样相加就有重复。
如果不算原来的就会有缺失,那么考虑缺失了哪些?
显然 (a) 中不能整除 (p) 的因子都会缺失,因为没有其他因子 (×p) 成为一个 “不能整除 (p) 的因子”。
那我们设 (e_i) 为 (i) 的因子中不能整除 (i) 的最小质因子的因子和。
这里有一个技巧,在线性筛判断整除的时候,如果 i%pri[j]==0
,这个 pri[j]
一定是 (i) 的最小质因子,因为他是第一个能整除的质数嘛。
容易得到,此时:
[varepsilon(a×p)=varepsilon(a)+e_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
的。