線性篩,積性函數,狄利克雷卷積,常見積性函數的篩法


一些性質

  • 積性函數:對於函數\(f(n)\),若滿足對任意互質的數字\(a,b,a*b=n\)\(f(n)=f(a)f(b)\),那么稱函數f為積性函數。
  • 狄利克雷卷積:對於函數f,g,定義它們的卷積為
    \((f∗g)(n)=\sum_{d|n}f(d)g(\frac{n}{d})\)
    狄利克雷卷積滿足很多性質:
    交換律:\(f∗g=g∗f\)
    結合律:\((f∗g)∗h=f∗(g∗h)\)
  • 兩個積性函數的狄利克雷卷積仍為積性函數。
  • 積性函數都可以用線性篩篩出來

怎么篩?
\(一般來講,只要知道f(P^k),P為質數,就可以知道怎么篩了\)
\(簡單來講就是推一下\)
\(通俗來講就是手玩一下或者打表找規律\)
如果你一眼就看出來了那就只能Orz了

幾道題

Bzoj4804: 歐拉心算
BZOJ2693jzptab
BZOJ4407 :於神之怒加強版

一些常見積性函數的篩法

莫比烏斯函數\(\mu(n)\)

這個比較簡單,\(\mu(1)=1\)\(i\)為質數時\(\mu(i)=-1\),最小質因子篩到它的時候正負號反過來,否則為\(0\)


	isprime[1] = 1; mu[1] = 1;
	for(int i = 2; i < N; ++i){
		if(!isprime[i]){  prime[++num] = i; mu[i] = -1;  }
		for(int j = 1; j <= num && i * prime[j] < N; ++j){
			isprime[i * prime[j]] = 1;
			if(i % prime[j]) mu[i * prime[j]] = -mu[i];
			else{  mu[i * prime[j]] = 0; break;  }
		}
	}

乘法逆元\(inv(i)\)

求一個數在模p意義下的逆元
\(p=i*x+j\),則\(i*x+j\equiv0(mod\ p)\)
同時除以\(i*j,所以x*j^{-1}+i^{-1}\equiv0(mod\ p)\)
移項\(i^{-1}\equiv-x*j^{-1}(mod\ p)\)
\(x=p\ div\ i,j=p\ mod\ i\)
所以\(inv(i)=-inv(p\%i)*(p/i)\)
不用篩了,遞推就可以了

inv[1] = 1; for(int i = 2; i < p; ++i) inv[i] = -(p / i) * inv[p % i] % p + p) % p;

補充階乘逆元的遞推,求出\(inv(n)\)\(inv(i)=inv(i+1)*(i+1)\)倒着來就行了

fac[0] = inv[0] = 1;
for(int i = 1; i <= n; ++i) fac[i] = fac[i] * i % p;
inv[n] = Getinv(fac[n]); //Exgcd or Fermat
for(int i = 1; i < n; i++) inv[i] = inv[i + 1] * (i + 1) % p;

歐拉函數\(\varphi(n)\)

公式:
\(n分解成若干質數p的乘積n=\Pi p_i^{a_i}\)
\(\varphi(n)=n*\Pi(1-\frac{1}{p_i})\)

那么\(\varphi(1)=1\)\(n為質數時\varphi(n)=n-1\),最小質因子篩到它時乘上質因子\(p-1\),否則乘上這個質數

isprime[1] = 1; phi[1] = 1;
	for(int i = 2; i < N; ++i){
		if(!isprime[i]){  prime[++num] = i; phi[i] = i - 1;  }
		for(int j = 1; j <= num && i * prime[j] < N; ++j){
			isprime[i * prime[j]] = 1;
			if(i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
			else{  phi[i * prime[j]] = phi[i] * prime[j]; break;  }
		}
	}

約數個數\(d(n)\)

公式:
還是分解
\(d(n)=\Pi(a_i + 1)\)

我們記錄下每個數最小質因子的指數記為\(pred\)就好了

isprime[1] = 1; d[1] = 1;
for(int i = 2; i < N; ++i){
	if(!isprime[i]){  prime[++num] = i; d[i] = 2; pred[i] = 1;  }
	for(int j = 1; j <= num && i * prime[j] < N; ++j){
		isprime[i * prime[j]] = 1;
		if(i % prime[j]){
			d[i * prime[j]] = d[i] * d[prime[j]];
			pred[i * prime[j]] = 1;
		}
		else{
			pred[i * prime[j]] = pred[i] + 1;
			d[i * prime[j]] = d[i] / (pred[i] + 1) * (pred[i] + 2);
			break; 
		}
	}
}

約數的和\(\sigma(n)\)

公式:
又是分解
\(\sigma(n)=\Pi(\sum_{j=0}^{a_i}p_i^j)\)

這個就很煩了。。。

也可以篩,開兩個個數組,一個\(powd\)記錄每個數最小質因子的指數次冪,另一個\(sumd\)記錄每個數最小質因子\(\sum_{i=0}^{a}p^i\)就可以了

我們把這個鬼里鬼氣的\(\sigma寫成f\)

isprime[1] = 1; f[1] = mu[1] = 1;
for(int i = 2; i < N; ++i){
	if(!isprime[i]){
		prime[++num] = i; f[i] = i + 1; mu[i] = -1;
		sumd[i] = 1 + i; powd[i] = i;
	}
	for(int j = 1; j <= num && i * prime[j] < N; ++j){
		isprime[i * prime[j]] = 1;
		if(i % prime[j]){
			sumd[i * prime[j]] = 1 + prime[j];
			powd[i * prime[j]] = prime[j];
			f[i * prime[j]] = f[i] * f[prime[j]];
		}
		else{
			powd[i * prime[j]] = powd[i] * prime[j];
			sumd[i * prime[j]] = sumd[i] + powd[i * prime[j]];
			f[i * prime[j]] = f[i] / sumd[i] * sumd[i * prime[j]];
			break;
		}
	}
}

完結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM