浅谈线性素数筛

  素数筛的用处还是蛮多的,有很多和素数有关的题都要用到素数筛,所以有一个高效的筛法自然是非常好的吖,普通筛法(暴力筛法)就不说了,因为有了高效的也没人在会用普通筛法了吧。

  线性素数筛是用每一个合数的最小的质因数筛掉它,这个体现在代码里的  if(i%prime[j]==0)break;  这句话里,因为如果这里不跳出的话,j会继续向上枚举,这时i*peime[j]的最小的质因数是之前的那个prime[j]而不是现在的prime[j],而一旦出现这样的情况,就不能保证每个数都被自己最小的质因数筛掉。而加上了那句话之后,时间复杂度保证就是线性的。

  模板:https://www.luogu.org/problemnew/show/P3383

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 int n,m;
 5 bool vis[10000003];
 6 int prime[1000003];
 7 int cnt;
 8 int main()
 9 {
10     scanf("%d%d",&n,&m);
11     vis[0]=vis[1]=1;
12     for(int i=2;i<=n;++i)
13     {
14         if(!vis[i])prime[++cnt]=i;
15         for(int j=1;j<=cnt&&i*prime[j]<=n;++j)
16         {
17             vis[i*prime[j]]=1;
18             if(i%prime[j]==0)break; 
19         }
20     }
21     while(m--)
22     {
23         int x;
24         scanf("%d",&x);
25         if(!vis[x])printf("Yes\n");
26         else printf("No\n");
27     } 
28     return 0;
29 }
View Code

  还有一个叫做区间素数筛的东西,窝也是前几天才知道的,不过不是线性的,或许有线性的写法吧,不太会,但是复杂度也不是很高。

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long 
 4 using namespace std;
 5 const int maxn=1000005;
 6 bool b1[maxn],b2[maxn];
 7 ll prime[maxn];
 8 ll cnt;//区间素数筛的原理:(a,b)区间的合数的最小质因数一定小于sqrt(b),\
 9 //所以把2到sqrt(b)的素数筛出来,蓝后,用他们把他们在a到b的倍数筛出来 
10 int main()
11 {
12     ll a,b;
13     scanf("%lld%lld",&a,&b);b++;
14     for(ll i=0;i*i<b;++i)b2[i]=1;
15     for(int i=0;i<b-a;++i)b1[i]=1;
16     for(ll i=2;i*i<b;++i)
17     {
18         if(b2[i])
19         {
20             for(ll j=2*i;j*j<b;j+=i)b2[j]=0;
21             for(ll j=max(2ll,(a+i-1)/i)*i;j<b;j+=i)b1[j-a]=0;
22         }
23     }
24     for(ll i=0;i<b-a;++i)
25         if(b1[i])prime[cnt++]=a+i;
26     printf("%d\n",cnt);
27 }
View Code

 

转载于:https://www.cnblogs.com/yuelian/p/8758876.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 线性法是一种常用的求数的方法,它的思想简单且高效。下面是使用Java语言实现线性法求数的代码: ```java import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class LinearSieve { public static List<Integer> getPrimes(int n) { boolean[] isComposite = new boolean[n + 1]; List<Integer> primes = new ArrayList<>(); for (int i = 2; i <= n; i++) { if (!isComposite[i]) { primes.add(i); } for (int j = 0; j < primes.size() && i * primes.get(j) <= n; j++) { isComposite[i * primes.get(j)] = true; if (i % primes.get(j) == 0) { break; } } } return primes; } public static void main(String[] args) { int n = 100; List<Integer> primes = getPrimes(n); System.out.println("从 2 到 " + n + " 的数为:"); for (int prime : primes) { System.out.print(prime + " "); } } } ``` 以上代码中,我们使用了一个布尔数组`isComposite`来标记是否为合数。初始时,将所有数都标记为非合数。然后从2开始,遍历到n,如果某个数i是合数,则跳过;如果是数,则将其加入到数列表中,并标记它的倍数为合数。遍历结束后,我们得到了从2到n的所有数。 在main函数中,我们设置n为100,调用`getPrimes`函数获取从2到100的数,并打印出来。 运行结果为:从 2 到 100 的数为:2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97。 ### 回答2: 线性法是一种高效地选出一定范围内的数的算法。下面是用Java实现线性法求数的代码: ```java import java.util.*; public class LinearSieve { public static List<Integer> sieve(int n) { boolean[] isPrime = new boolean[n + 1]; Arrays.fill(isPrime, true); // 将所有数初始化为数 List<Integer> primes = new ArrayList<>(); for (int i = 2; i <= n; ++i) { if (isPrime[i]) { primes.add(i); // 将数加入结果列表 } for (int j = 0; j < primes.size() && i * primes.get(j) <= n; ++j) { isPrime[i * primes.get(j)] = false; // 将当前数倍数标记为非数 if (i % primes.get(j) == 0) { break; // 若当前数为数倍数,跳出内层循环 } } } return primes; } public static void main(String[] args) { int n = 100; // 范围上限 List<Integer> primes = sieve(n); System.out.println("范围[2, " + n + "]内的数有:"); for (int prime : primes) { System.out.print(prime + " "); } } } ``` 通过线性法,我们首先将所有数初始化为数,然后从2开始,将每个数的倍数标记为非数,直到选结束。最后,将选出的数存入结果列表中。在上述代码中,我们以100为例,调用`sieve`方法求解范围内的数,并输出结果。 当我们运行上述代码时,将会得到范围[2, 100]内的数列表: ``` 范围[2, 100]内的数有: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ``` 以上就是使用Java实现线性法求数的代码及结果。 ### 回答3: 线性法是一种用于求解数的算法,可以高效地找出某一个范围内的所有数。下面是使用Java语言实现线性法求数的代码: ```java import java.util.ArrayList; import java.util.List; public class PrimeNumbers { public static List<Integer> getPrimeNumbers(int n) { List<Integer> primeNumbers = new ArrayList<>(); boolean[] isComposite = new boolean[n + 1]; for (int i = 2; i <= n; i++) { if (!isComposite[i]) { primeNumbers.add(i); } for (int j = 0; j < primeNumbers.size() && i * primeNumbers.get(j) <= n; j++) { isComposite[i * primeNumbers.get(j)] = true; if (i % primeNumbers.get(j) == 0) { break; } } } return primeNumbers; } public static void main(String[] args) { int n = 100; List<Integer> primeNumbers = getPrimeNumbers(n); System.out.println("在[2, " + n + "]范围内的数有:"); for (int number : primeNumbers) { System.out.println(number); } } } ``` 这段代码使用了一个布尔数组isComposite来记录某个数是否为合数(非数),初始时假设所有数都是质数,然后从2开始遍历到n,如果某个数i没有被标记为合数,就将其添加到数列表中,并将i与已有的质数依次相乘,将其标记为合数。 运行以上代码,可以求解出2到100之间的所有数。输出结果如下: ``` 在[2, 100]范围内的数有: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ``` 通过线性法,我们可以高效地找到某个范围内的数,而不需要遍历所有的数进行判断。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值