素数筛选法(线性筛法模板)

线性筛法

#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int main()
{
    memset(flag,1,sizeof(flag));//假设全是素数
    flag[0]=0;flag[1]=0;//0和1不是素数
    int index=0;
    for(int i=2;i<=N;i++)
    {
        if(flag[i])prime[index++]=i;//得到素数集合
        for(int j=0;j<index&&prime[j]*i<=N;j++)
        {
            flag[prime[j]*i]=0;//筛合数
            if(i%prime[j]==0)break;//只筛合数的素因子最小的那一个
        }
    }
    return 0;
}

复杂度为O(n),得到素数集合prime[],flag[i]判断i是不是素数,也可以让flag[i]=index+1,flag的值就保存了i是第几个素数

nefu 1262 五十弦翻塞外声

这题好难哦,解题思路:唯一分解定理:举个例子:18的因子和

素因子为332,因子和为(3^2 + 3^1 + 3^0) * (2^1 +2^0)=39

所以可以用一个二维数组(或者结构体)把素因子及其幂存起来,最后用等比数列求和公式a1*(q^n-1)/(q-1),a1都是1

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int prime[78500];
bool f[1000000];
const int N=1e6;
void data()
{
    int cnt=0;
    memset(f,1,sizeof(f));
    for(int i=2;i<N;i++)
    {
        if(f[i])prime[cnt++]=i;
        for(int j=0;j<cnt&&prime[j]*i<N;j++)
        {
            f[i*prime[j]]=0;
            if(i%prime[j]==0)break;
        }
    }
}
//快速幂不取模
ll quick(ll a,int n)
{
    ll ans=1;
    while(n)
    {
        if(n&1)ans=ans*a;
        n>>=1;
        a=a*a;

    }
    return ans;
}
int main()
{
    data();//很重要,不然data()函数就没用
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        int a[20][2],cnt=0,i=0;
        scanf("%d",&n);
        while(n!=1&&i<=3401)
        {
            if(n%prime[i]==0)
            {
                a[cnt][1]=0;
                while(n%prime[i]==0)
                {
                    n/=prime[i];
                    a[cnt][1]++;
                }
                a[cnt++][0]=prime[i];
            }
            i++;
        }
        if(n!=1)
        {
            a[cnt][1]=1;
            a[cnt++][0]=n;
        }
        ll ans=1;
        //等比数列依次累乘求和
        for(int i=0;i<cnt;i++)
        {
            ans*=(quick((ll)a[i][0],a[i][1]+1)-1)/(a[i][0]-1);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

nefu 825 函数版素数判定

变化不大,简单题

#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int main()
{
    memset(flag,1,sizeof(flag));//假设全是素数
    int index=0;
    flag[1]=0;
    flag[0]=0;
    for(int i=2;i<=N;i++)
    {
        if(flag[i])prime[index++]=i;//得到素数集合
        for(int j=0;j<index&&prime[j]*i<=N;j++)
        {
            flag[prime[j]*i]=0;//筛合数
            if(i%prime[j]==0)break;//只筛合数的素因子最小的那一个
        }
    }
    int n;
    while(~scanf("%d",&n))
    {
        if(flag[n])printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

nefu 585 最大素因子

也变化不大,依次去掉最高位,判断是不是素数

#include <bits/stdc++.h>
using namespace std;
int a[1000005],b[1000005];
int main()
{
    int n,m,cnt;
    memset(a,1,sizeof(a));
    for(int i=2;i<=1000000;i++)
    {
        if(a[i]!=0)
        for(int j=2;i*j<=1000000;j++)a[i*j]=0;
    }
    cnt=0;
    for(int i=2;i<=1000000;i++)
    {
        if(a[i]!=0)b[++cnt]=i;
    }
    while(cin>>n)
    {
        int sum=0;
        if(n==1){cout<<"0"<<endl;continue;}
        for(int i=cnt;i>=1;i--)
        {
            if(n%b[i]==0){cout<<i<<endl;break;}
        }
    }
    return 0;
}

nefu 586 纯素数

发现组数多的时候,cin和cout都挺占时间的,一开始用cout都tle了

#include <bits/stdc++.h>
using namespace std;
const int N=1e6;
bool flag[N+10];
int prime[N+10];
int main()
{
    int n;
    memset(flag,1,sizeof(flag));//假设全是素数
    int index=0;
    for(int i=2;i<N;i++)
    {
        if(flag[i])prime[index++]=i;//得到素数集合
        for(int j=0;j<index&&prime[j]*i<N;j++)
        {
            flag[prime[j]*i]=0;//筛合数
            if(i%prime[j]==0)break;
        }
    }
    flag[0]=0,flag[1]=0;

    while(~scanf("%d",&n))//当输入组数大于10000时,cout cin一般都很占时间
    {
        if(!flag[n]){printf("NO\n");continue;}
        int A=1e5;
        int flag0=1;
        for(int i=0;;i++)
        {
            n=n%A;
            if(!flag[n]){flag0=0;break;}
            A=A/10;
            if(n<10)break;
        }
        if(flag0==1)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
}

nefu 587 半素数

这题卡时间,思路:两个素数相乘小于N,用数组标记,一重循环小于sqrt(N),可以避免重复,减少时间

#include <bits/stdc++.h>
using namespace std;
const int N=1e6;//为啥是2e6才行呢1e6居然不行
int flag[N+10];
int prime[N+10];
int flag0[N];
int main()
{
    memset(flag,1,sizeof(flag));//假设全是素数
    int index=0;
    for(int i=2;i<N;i++)
    {
        if(flag[i]){prime[index++]=i;flag[i]=index;}
        for(int j=0;j<index&&prime[j]*i<N;j++)
        {
            flag[prime[j]*i]=0;//筛合数
            if(i%prime[j]==0)break;//只筛合数的素因子最小的那一个
        }
    }
    flag[1]=0;
    int n;
    for(int i=0;prime[i]<sqrt(N*1.0);i++)
    {
        for(int j=i;prime[j]*prime[i]<N;j++)
        {
            flag0[prime[j]*prime[i]]=1;
        }
    }
    while(~scanf("%d",&n))
    {
        if(flag0[n])printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

nefu781 素数与数论

用到一个小技巧flag[n]本来是用来判断是否是素数的,可以让flag也存上这个素数是第几个素数,然后找x开始为素数的下标与y+1开始的下标,相减就是之间的素数个数

#include <bits/stdc++.h>
using namespace std;
const int N=2e6;//为啥是2e6才行呢1e6居然不行
int flag[N+10];
int prime[N+10];

int main()
{
    memset(flag,1,sizeof(flag));//假设全是素数
    int index=0;
    for(int i=2;i<N;i++)
    {
        if(flag[i]){prime[index++]=i;flag[i]=index;}
        for(int j=0;j<index&&prime[j]*i<N;j++)
        {
            flag[prime[j]*i]=0;//筛合数
            if(i%prime[j]==0)break;//只筛合数的素因子最小的那一个
        }
    }
    flag[1]=0;
    int x,y,sum;
    while(~scanf("%d %d",&x,&y))
    {
        sum=0;
        int i,j;
        for(i=x;;i++)
        {
            if(flag[i]){i=flag[i];break;}
        }
        for(j=y+1;;j++)if(flag[j]){j=flag[j];break;}
        sum=j-i;
        cout<<sum<<endl;
    }
    return 0;
}

nefu1704 知否知否,应是绿肥红瘦

判断1e14大小的素数的方法:用线性筛求出1e7以内的素数再判断这个数能否被前面的素数整除,不能则是素数

#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int su(long long n)//对1e7内素数,能整除不是素数
{
    int flag=0;//假设是素数
    for(int i=0;prime[i]<=sqrt(1.0*n);i++)
    {
        if(n%prime[i]==0){flag=1;break;}
    }
    if(n==1)flag=1;
    return flag;
}
int main()
{
    memset(flag,1,sizeof(flag));//假设全是素数
    int index=0;
    for(int i=2;i<N;i++)
    {
        if(flag[i])prime[index++]=i;//得到素数集合
        for(int j=0;j<index&&prime[j]*i<N;j++)
        {
            flag[prime[j]*i]=0;//筛合数
            if(i%prime[j]==0)break;//只筛合数的素因子最小的那一个
        }
    }
    int n;
    scanf("%d",&n);
    long long a,b,c,sum;
    while(n--)
    {
        scanf("%lld %lld %lld",&a,&b,&c);
        sum=a+b-c;
        if(su(sum)==0)printf("yes\n");
        else printf("no\n");
    }
    return 0;
}

nefu 2113 素数线性筛

这题非常简单就是套模板就行

#include <bits/stdc++.h>
using namespace std;
const int N=1e7;
bool flag[N+10];
int prime[N+10];
int main()
{
    memset(flag,1,sizeof(flag));//假设全是素数
    int index=0;
    for(int i=2;i<N;i++)
    {
        if(flag[i])prime[index++]=i;//得到素数集合
        for(int j=0;j<index&&prime[j]*i<N;j++)
        {
            flag[prime[j]*i]=0;//筛合数
            if(i%prime[j]==0)break;
        }
    }
    int n,q;
    scanf("%d %d",&n,&q);
    int a;
    while(q--)
    {
        scanf("%d",&a);
        printf("%d\n",prime[a-1]);
    }
    return 0;
}
  • 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、付费专栏及课程。

余额充值