积性函数

积性函数

引入:

我们在线性筛质数的时候使用的方法是这样的

void GetPrime(int n){
    memset(isPrime, 1, sizeof(isPrime));
    isPrime[1] = 0;//1不是素数
    for(int i = 2; i <= n; i++){
        if(isPrime[i])
            Prime[++cnt] = i;
        for(int j = 1; j <= cnt && i*Prime[j] <= n; j++) {
            isPrime[i*Prime[j]] = 0;
            if(i % Prime[j] == 0)
                break; 
        }
    }
}

在这个程序里面我们保证一些东西:

1. imodPrime[j]==0 时候 Prime[j] 一定是 i 的最小质因子

从小到大枚举 Prime[j] 这显而易见

2.i×Prime[j]Prime[j] 一定是最小质因子

x=i×Prime[j]

如果有更小的质因子 p ,那么一定满足 imodp=0 会在前面直接判断跳出循环

3. x 一定被筛一次并且被他的最小质因子筛

积性函数:

定义:一个数是积性函数当且仅当:

f(nm)=f(n)f(m)    (gcd(m,n)=1)

而在积性函数中,经常使用到以下几个重要的积性函数(容易证明它们都是积性的):
    • τ(n) 表示正整数 n 的正因子个数。
    • σ(n) 表示正整数 n 的正因子和。
    • μ(n) 表示正整数 n 的 Mobius 函数值。
    • φ(n) 表示正整数 n 的欧拉函数值,即 [1, n] 中与 n 互质的数的个数。

积性函数一般搭配线性筛用

我在这里以 τ(n) 为例子

f(nm)=f(n)f(m)    (gcd(m,n)=1)

可以直接相乘

imodPrime[j]==0

我们设 x=i,y=prime[j]

那么一定有

x=k×ym

那么可以表示为

x×y=k×ym+1

这样 kym+1 一定互质,可以直接相乘

但假如 i=16,Prime[j]=2

那么 k=1,ym+1=32

我们并没有算出 32 的函数值,怎么办呢?

我们可以发现 ym+1 的特性,他的因子一定是

y0,y1,y2...ym+1

函数值就直接等于 m+2

这样就有了以下代码

void pre(){
	a[1] = 1;
	for(int i = 2;i <= N; ++i){
		isP[i] = 1;
	}
	for(int i = 2;i <= N; ++i){
		if(isP[i] == 1){
			prime[++tot] = i;
			a[i] = 2;//如果是质数一定有两个因子
		}
		for(int j = 1;j <= tot && prime[j] * i <= N - 10; ++j){
			isP[prime[j] * i] = 0;
			if(i % prime[j] == 0){
				int add = 0,sum = 0,x = i,y(prime[j]);
				while(x % y == 0){
					x = x / y;
					add++;
				} 
				a[prime[j] * i] = a[x] * (2 + add);
				break;
			}
			a[prime[j] * i] = a[prime[j]] * a[i];
		}
	}
}

但时间复杂度变成了 O(nlogn) ,如何优化?

我们记录 addi 表示 i 的最小质因子,就可以用空间换时间:

具体代码实现如下

void pre(){
	a[1] = 1;
	for(int i = 2;i <= N; ++i){
		isP[i] = 1;
	}
	for(int i = 2;i <= N; ++i){
		if(isP[i] == 1){
			prime[++tot] = i;
			a[i] = 2;//如果是质数一定有两个因子
            add[i] = 1;//注意
		}
		for(int j = 1;j <= tot && prime[j] * i <= N - 10; ++j){
			isP[prime[j] * i] = 0;
			if(i % prime[j] == 0){
				int x = i,y(prime[j]);
                add[i * prime[j]] = add[i] + 1;//注意
				a[prime[j] * i] = a[x/(add[i])] * (1 + add[i]);//注意
				break;
			}
			a[prime[j] * i] = a[prime[j]] * a[i];
            add[i * prime[j]] = 1;//注意
		}
	}
}
posted @   He_Zi  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示