线性筛积性函数学习笔记
以求解下面这个问题为例,对于任给的n,请求出下列式子的结果,1<=n<=1e7
\\\sum_{i=1}\^{n}\\sum_{j=1}\^{n} (-1)\^{d(i\\cdot j)} \\
cpp
const int N=1e7+5,MOD=998244353;
int f[N],K[N],vis[N];
vi pm;
/*
要计算ΣΣ(-1)^(d(i*j))
d(n)只有在n为完全平方数时才会是奇数
令n=x*(y*y),x不含任何平方因子(1除外)
则d(i*j)为奇数当且仅当i=x*(y*y),且j=x*(z*z) |此时d(i*j)=(x*y*z)*(x*y*z),是奇数
所以令f(n)=x;
只需求f(i)=f(j)的对数即可,答案就是这个n*n-所有f相同的对数
进一步转化为求f(x)的所有取值的种数
当x为p^k时,若k&1,则f(x)=p,否则f(x)=1------------------*
f(x)是积性函数
怎么利用线性筛求解f(x)
PS:线性筛是在i=n/pn,pm[j]=pn时筛到n的,其中pn是n的最小质因子
考虑新增一个K[]数组,K[n]表示n有多少个pn因子,(n有多少个最小质因子,例如K[12]=2)
进一步的为了方便计算,我们可以把K[n]表示为pn^k,例如K[12]=4,K[18]=9
如果pn|(n/pn),K[n]=K[n/pn]*pn,否则K[n]=pn
容易发现这样的K[n]和(n/K[n])一定互质
但是也有可能出现n=K[n]的情况,这个时候f[n]可以通过*处求解 即f(n)=pn/f(n/K[n])
若n!=K[n],则f(n)=f(K[n])*f(n/K[n])
这样理清之后就有了下面的代码
*/
void init(){
vis[1]=1;
int n=1e7;
f[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
pm.pb(i);
K[i]=i;
f[i]=i;
}
for(int p:pm){ //下面的i*p就是n
if(p*i>n) break;
vis[p*i]=1;
if(i%p==0){ // pn | n/pn
K[i*p]=K[i]*p;
if(i*p==K[i]*p){//n=pn^k
f[i*p]=p/f[i];
}else{
f[i*p]=f[i*p/K[i*p]]*f[K[i*p]];
}
break;
}else{
K[i*p]=p;
f[i*p]=f[p]*f[i];
//f[i*p]=f[i*p/K[i*p]]*f[K[i*p]]; <--写成这样也是等价的
}
}
}
}
void cal(){//这是一种化简后的形式
int n=1e7;
f[1]=1;
for(int i=2;i<=n;i++){
if(!f[i]){
pm.pb(i);
f[i]=i;
}
for(int p:pm){
if(p*i>n) break;
if(f[i]%p==0){
f[i*p]=f[i]/p;
}else f[i*p]=f[i]*p;
if(i%p==0) break;
}
}
}