【数学的奥秘】 线性筛法 无水整理版(欧拉筛法+ 质因数个数筛法)

版权声明:版权所有……啊重点是我简直找不到第二个人写比我还多的吐槽-。- https://blog.csdn.net/StrongerIrene/article/details/82352595

所谓线性?

就像我们的世界是二进制的,数学的世界其实也是由素数组成的

一个数,要么是素数,要么是有很多素数相乘组成的,基于这些原理,来介绍和探索欧拉筛法

代码:(补充)

欧拉筛法之所以达到的是线性  是因为被筛除掉的过程唯一  而如何达到的唯一  其实就是那句break保证的
其实就是  根本原因是这个世界的数字是由无数个质因数相城而来的 
筛法的本质就在于用最小的质因数来筛选
比如18  2*3*3 可以在2*3  就是6的时候标记掉  但是6/2是0 已经break了   3*3检验2的时候才是标记18的地方
这样就保证了只标记一次
近似线性
当然  如果有一个新的质数  首先会和前面各个质数组成一些新的合数
这个时候就要等于该质数本身的时候break
那么问题来了,以2*3*3*5为例 根据推论我们知道它只能是由3*3*5标记来的
3*3*5是3*5标记来的
3*5是5第一次出现的时候为了拉拢关系,跟它前面的每个素数都送礼结合而来的
这个过程就像是海绵一样,拆除质数就是把水分挤干
接下来还有边界问题,每次标记一两个,最后越界了怎么办?不好证,但是有一些显然结论
即,若得到答案越界,直接break,以及每次进行筛的时候,都选了正好比她大的合数
另外,直接晒到maxn-5,让所以没被标记的素数,浮出水面
所以可以感觉到它的确是安全的

 
int primes[MAXN],tot=0;
bool isPrime[MAXN];
 
void getPrime()
{
    memset(isPrime,true,sizeof(isPrime));
    for(int i=2;i<MAXN;i++)
    {
        if(isPrime[i])
            primes[++tot]=i;
        for(int j=1;j<=tot;j++)
        {
            if(i*primes[j]>=MAXN) break;
            isPrime[i*primes[j]]=false;
            if(i%primes[j]==0) break;//*****
        }
    }
}
 

想到这个,是基于南京icpc赛里面,先筛出质因数

函数在此:关键是d[i] d[i]里面就是质因数的个数

在此特别注意质因数:8有1个质因数,6却有2个,这就是2*2*2和2*3的差别

举个例子,如果是30,2*3*5 ,有3个质因数,它不是由6规划来的,因为6在有了2*3之后只去标记了6*2,就没掉了

而是由3*5标记来的,这也符合筛法,筛法里面我推断出的“由最小质因数搞过来的,不然就是浪费呀!”

上代码

void getprime()//先求素因数个数
 {
     cnt=0;
     for(int i=2;i<=maxn-5;++i)
     {
         if(!vis[i])
         {//在遍历的过程中如果是1的话,那么因子个数是1,这些是没错的
             prime[++cnt]=i;
             d[i]=1;
         }
		 for(int j=1;j<=cnt&&i*prime[j]<=maxn-5;++j)
		 {
			 vis[i*prime[j]]=1;
             if (!(i%prime[j]))// ==0  chudejin
             {
                 d[i*prime[j]]=d[i]; 
                 break;
             }
	         d[i*prime[j]]=d[i]+1;
         }
     }
 
 }
 

其实还有个num,不知是干嘛的
 

猜你喜欢

转载自blog.csdn.net/StrongerIrene/article/details/82352595