zoukankan      html  css  js  c++  java
  • 一点线性筛的东西

    线性筛

    (csp)还有不到一个月。
    才发现自己不会线性筛,(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})
    枚举的(i)(frac{n}{p_1})
    (n\%pri[j]==0) 就是说枚举到了(pri[j]*i)的最小质因子的边界了。
    再往后的(pri[j])就会比(i)里面的质因子小了,当然不行了。
    之前的质因子都是小于(i)的质因子,当然行了。
    (n\%pri[j]==0)就是恰好相等的时候。
    可以很方便的求积性函数,只需要毒瘤的简单的分类讨论就好了。

    求莫比乌斯函数

    [ mu(x)=left{ egin{aligned} & 1& n=1 \ & (-1)^k& n=p_1*p_2…p_k \ & 0& n=others end{aligned} ight. ]

    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];
    	}
    }
    

    那些

    [ sum_{d|n}mu(d)=left{ egin{aligned} & 1& n=1 \ & 0& n>1 end{aligned} ight. ]

    这个二项式定理啥的证
    (sum_{i=0}^{k}(-1)^kC_k^i).

    求欧拉函数

    (phi(n))(n)互质的数的个数
    之前写的懒得敲了。

    TIM图片20191014160010.jpg

    筛的主要还是利用(n*frac{p_1-1}{p_1}……frac{p_k-1}{p_k})

    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);
    	}
    }
    

    [sum_{d|n}phi(d)=n ]

    咱不会证,咱也不想想.

    约数个数

    如果 (x=p_1^{c_1}p_2^{c_2}...p_k^{c_k}) ,则 (d(x)=(1+c_1)(1+c_2)...(1+c_k))
    筛的过程中,我们记录一个 (num(x)) 表示 (x) 的最小质因子的个数,即 (c_1)
    然后(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的约数和。
    (sd(n)=(1+p_1+…+p_1^{r_1})*(1+p_2+…+p_2^{r_2})*…*(1+p_k…+p_k^{r_k}))
    等差数列似的一个东西。
    这个时候我们需要记录最小质因子的那一项也就是((1+p_x+p_x^2+……+p_x^{r_1})),叫他(num(i)).可以设sd(i)表示i的约数和。设
    (一),当前数是一个素数:
    (sd(i)=i+1)
    (num(i)=i+1)
    (二),当前数取模枚举的质数不等于0
    ((i*prime[j]))里原先没有((prime[j]))这一项,加上这一项之后可得:(sd(i*prime[j])=sd(i)*sd(prime[j]))
    (num(i*prime[j])=1+prime[j])
    (三),当前数取模枚举的质数等于0
    (sd(i*prime[j])=sd(i)/num(i)*(num(i)*prime[j]+1))
    (num(i*prime[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;
    		}
    	}
    }
    
  • 相关阅读:
    ARC 基础(上)
    将字符串写到屏幕上
    UIColor 详解
    the complexity is no longer O(lgn), right?
    [LeetCode] Sum Root to Leaf Numbers, Solution
    [LeetCode] Word Ladder II, Solution
    [Microsoft] Intealeaving of two given strings, Solution
    [Yahoo] Cloest palindrome number, Solution
    [LeetCode] Longest Consecutive Sequence, Solution
    Summary
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/11672679.html
Copyright © 2011-2022 走看看