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

线性筛法

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值