一点线性筛的东西

文章目录

    • 线性筛
      • 求莫比乌斯函数
      • 求欧拉函数
      • 约数个数
      • 约数和

线性筛

c s p csp csp还有不到一个月。
才发现自己不会线性筛, m d z z mdzz mdzz.
(代码都没试过,请谨慎使用)

for(int i=2;i<=n;++i) {
	if(!vis[i]) pri[++cnt]=i;
	for(int j=1;j<=cnt&&i*pri[j]<=n;++j) {
		vis[i*pri[j]]=1;
		if(i%pri[j]==0) break;
	}
}

只会被最小的素数筛掉。
n = p 1 k 1 ∗ p 2 k 2 … … p x k x n=p_1^{k_1}*p_2^{k_2}……p_x^{k_x} n=p1k1p2k2pxkx
枚举的 i i i n p 1 \frac{n}{p_1} p1n
n % p r i [ j ] = = 0 n\%pri[j]==0 n%pri[j]==0 就是说枚举到了 p r i [ j ] ∗ i pri[j]*i pri[j]i的最小质因子的边界了。
再往后的 p r i [ j ] pri[j] pri[j]就会比 i i i里面的质因子小了,当然不行了。
之前的质因子都是小于 i i i的质因子,当然行了。
n % p r i [ j ] = = 0 n\%pri[j]==0 n%pri[j]==0就是恰好相等的时候。
可以很方便的求积性函数,只需要毒瘤的简单的分类讨论就好了。

求莫比乌斯函数

μ ( x ) = { 1 n = 1 ( − 1 ) k n = p 1 ∗ p 2 … p k 0 n = o t h e r s \mu(x)=\left\{ \begin{aligned} & 1& n=1 \\ & (-1)^k& n=p_1*p_2…p_k \\ & 0& n=others \end{aligned}\right. μ(x)=1(1)k0n=1n=p1p2pkn=others

mu[1]=1;
for(int i=2;i<=n;++i) {
	if(!vis[i]) {
		pri[++cnt]=i;
		mu[i]=-1;
	}
	for(int j=1;j<=cnt&&i*pri[j]<=n;++j) {
		vis[i*pri[j]]=1;
		if(i%pri[j]==0) {
			mu[i*pri[j]]=0;
			break;
		} else mu[i*pri[j]]=-mu[i];
	}
}

那些
∑ d ∣ n μ ( d ) = { 1 n = 1 0 n > 1 \sum_{d|n}\mu(d)=\left\{ \begin{aligned} & 1& n=1 \\ & 0& n>1 \end{aligned}\right. dnμ(d)={10n=1n>1
这个二项式定理啥的证
∑ i = 0 k ( − 1 ) k C k i \sum_{i=0}^{k}(-1)^kC_k^i i=0k(1)kCki.

求欧拉函数

ϕ ( n ) \phi(n) ϕ(n) n n n互质的数的个数
之前写的懒得敲了。
一点线性筛的东西_第1张图片
一点线性筛的东西_第2张图片
一点线性筛的东西_第3张图片
筛的主要还是利用 n ∗ p 1 − 1 p 1 … … p k − 1 p k n*\frac{p_1-1}{p_1}……\frac{p_k-1}{p_k} np1p11pkpk1

phi[1]=1;
for(int i=2;i<=n;++i) {
	if(!vis[i]) {
		pri[++cnt]=i;
		phi[i]=i-1;
	}
	for(int j=1;j<=cnt&&i*pri[j]<=n;++j) {
		vis[i*pri[j]]=1;
		if(i%pri[j]==0) {
			phi[i*pri[j]]=phi[i]*pri[j];
			break;
		} else phi[i*pri[j]]=phi[i]*(pri[j]-1);
	}
}

∑ d ∣ n ϕ ( d ) = n \sum_{d|n}\phi(d)=n dnϕ(d)=n
咱不会证,咱也不想想.

约数个数

如果 x = p 1 c 1 p 2 c 2 . . . p k c k x=p_1^{c_1}p_2^{c_2}...p_k^{c_k} x=p1c1p2c2...pkck ,则 d ( x ) = ( 1 + c 1 ) ( 1 + c 2 ) . . . ( 1 + c k ) d(x)=(1+c_1)(1+c_2)...(1+c_k) d(x)=(1+c1)(1+c2)...(1+ck)
筛的过程中,我们记录一个 n u m ( x ) num(x) num(x) 表示 x x x 的最小质因子的个数,即 c 1 c_1 c1
然后 x j b xjb xjb转移

for(int i=2;i<=n;++i) {
	if(!vis[i]) {
		pri[++cnt]=i;
		num[i]=1;
		d[i]=2;
	}
	for(int j=1;j<=cnt&&i*pri[j]<=n;++j) {
		vis[i*pri[j]]=1;
		if(i%pri[j]==0) {
			num[i*pri[j]]=num[i]+1;
			d[i*pri[j]]=d[i]/(num[i]+1)*(num[i*pri[j]]+1);
			break;
		} else {
			num[i*pri[j]]=1;
			d[i*pri[j]]=d[i]*2;
		}
	}
}

约数和

我们设sd(i)表示i的约数和。
s d ( n ) = ( 1 + p 1 + … + p 1 r 1 ) ∗ ( 1 + p 2 + … + p 2 r 2 ) ∗ … ∗ ( 1 + p k … + p k r k ) sd(n)=(1+p_1+…+p_1^{r_1})*(1+p_2+…+p_2^{r_2})*…*(1+p_k…+p_k^{r_k}) sd(n)=(1+p1++p1r1)(1+p2++p2r2)(1+pk+pkrk)
等差数列似的一个东西。
这个时候我们需要记录最小质因子的那一项也就是 ( 1 + p x + p x 2 + … … + p x r 1 ) (1+p_x+p_x^2+……+p_x^{r_1}) (1+px+px2++pxr1),叫他 n u m ( i ) num(i) num(i).可以设sd(i)表示i的约数和。设
(一),当前数是一个素数:
s d ( i ) = i + 1 sd(i)=i+1 sd(i)=i+1
n u m ( i ) = i + 1 num(i)=i+1 num(i)=i+1
(二),当前数取模枚举的质数不等于0
( i ∗ p r i m e [ j ] ) (i*prime[j]) (iprime[j])里原先没有 ( p r i m e [ j ] ) (prime[j]) (prime[j])这一项,加上这一项之后可得: s d ( i ∗ p r i m e [ j ] ) = s d ( i ) ∗ s d ( p r i m e [ j ] ) sd(i*prime[j])=sd(i)*sd(prime[j]) sd(iprime[j])=sd(i)sd(prime[j])
n u m ( i ∗ p r i m e [ j ] ) = 1 + p r i m e [ j ] num(i*prime[j])=1+prime[j] num(iprime[j])=1+prime[j]
(三),当前数取模枚举的质数等于0
s d ( i ∗ p r i m e [ j ] ) = s d ( i ) / n u m ( i ) ∗ ( n u m ( i ) ∗ p r i m e [ j ] + 1 ) sd(i*prime[j])=sd(i)/num(i)*(num(i)*prime[j]+1) sd(iprime[j])=sd(i)/num(i)(num(i)prime[j]+1)
n u m ( i ∗ p r i m e [ j ] ) = n u m ( i ) ∗ p r i m e [ j ] + 1 num(i*prime[j])=num(i)*prime[j]+1 num(iprime[j])=num(i)prime[j]+1

sd[1]=1;
for(int i=2;i<=n;++i) {
	if(!vis[i]) {
		pri[++cnt]=i;
		num[i]=sd[i]=i+1;
	}
	for(int j=1;j<=cnt&&i*pri[j]<=n;++j) {
		vis[i*pri[j]]=1;
		if(i%pri[j]==0) {
			sd[i*pri[j]]=sd[i]/num[i]*(num[i]*pri[j]+1);
			num[i*pri[j]]=num[i]*pri[j]+1;
			break;
		} else {
			sd[i*pri[j]]=sd[i]*sd[pri[j]];
			num[i*pri[j]]=pri[j]+1;
		}
	}
}

你可能感兴趣的:(一点线性筛的东西)