积性函数
积性函数:互素的两个数,f(ab)=f(a)f(b)
完全积性函数:任意的两个数,f(ab)=f(a)f(b)
性质
如果f是完全积性函数
f(n)=f(p1)^e1 * f(p2)^e2 * ... * f(pr)^er
欧拉函数、莫比乌斯函数、因子个数函数都是积性函数,但不一定完全积性
线性筛
作用:
1、在O(n)的时间内求出n以内的所有素数
2、用于在线性时间内求出积性函数值
保证了每一个n都被他最小的质因数筛掉
利用线性筛求积性函数时,需要处理三种情况
1、f(p),p是素数
2、f(p*i), 其中p不是i的约数,根据积性函数性质直接等于f(p)f(i)
3、f(p*i),其中p是i的约数,需要利用函数各自的性质,不如说是寻找到 f(p^k)与f(p^(k-1))的递推关系,可以这么思考的原因是因为i里面已经蕴含了f(p^(k-1))(积性函数),这样我们只要找到递推关系式就可以直接搞出来
积性函数的关键是如何求 f(p^k)
1、观察线性筛法中的步骤,筛掉的同时还得到了它最小的质因数p,我们希望能够知道p在n中的次数,这样就能利用
f(n)=f(p^k) * f(n/(p^k))求出f(n)
2、令n=p*m,由于p是n最小的质因数,若p^2|n,则p|m,并且p也是m最小的质因数。
这样在进行筛法的同时,记录每个合数最小质因数的次数(有的时候要记有的时候不要记),就能算出新筛去合数最小质因数的次数
那么我们来举个例子
phi[p^k]=p*phi[p^(k-1)]=(p-1)*p^(k-1),证明暂时略
mu[p^k]=0,当k>=2的时候
所以下面给出代码
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int MAXN=1000005;
bool vis[MAXN];
ll mu[MAXN];
int i,n,T;
ll prime[MAXN];
ll phi[MAXN];
int Cs[MAXN]; // 用于保存每个
ll f[MAXN];
ll la,lb,ra,rb,k,p,ans,d,extra;
void Get_mu(int n)
{
int cnt=0;
memset(vis,0,sizeof(vis));
memset(mu,0,sizeof(mu));
mu[1]=1; // 积性函数f(1)肯定都是一
for(int i=2;i<n;i++) {
if(!vis[i]) {
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<n;j++) {
ll k=i*prime[j];
vis[k]=1;
if(i%prime[j]==0) {
mu[k]= 0;
break;
}
else mu[k]=-mu[i];
}
}
}
void Get_phi(int n)
{
int cnt=0;
memset(vis,0,sizeof(vis));
memset(prime,0,sizeof(prime));
memset(phi,0,sizeof(phi));
phi[1]=1;
for(int i=2;i<n;i++) {
if(!vis[i]) {
prime[cnt++]=i;
phi[i]=i-1;
}
for(int j=0;j<cnt&&i*prime[j]<n;j++) {
ll k=i*prime[j];
vis[k]=1;
if(i%prime[j]==0) {
phi[k]=phi[i]*prime[j];
break;
}
else phi[k]=phi[i]*(prime[j]-1);
}
}
}
int main() {
Get_mu(MAXN-5);
Get_phi(MAXN-5);
return 0;
}