东北林业大学acm大一培训(素数筛)

1.不知名筛选 筛法的思想是去除要求范围内所有的合数,剩下的就是素数
了,而任何合数都可以表示为素数的乘积,因此如果已知一
个数为素数,则它的倍数都为合数。
在这里插入图片描述
2.埃氏筛 合数的倍数一定会在筛素数倍数时候被筛掉,所以只筛素数就好,只把质数的素
数筛掉 就是找到一个质数,把它的倍数全部标记为合数。但是你会发现有的数
字会被标记多次,比如 12 被 2 ,3 ,都标记,这样会浪费时间。
在这里插入图片描述
3.线性筛 素数筛可 以优化,普通的线性筛法虽然大大缩短了求素数的时间,
但是实际上还是做了许多重复运算,比如23=6,在素数2的时候筛选了一遍,
在素数为3时又筛选了一遍。如果只筛选小于等于素数i的素数与i的乘积,
既不会造成重复筛选,又不会遗漏。时间复杂度几乎是线性的
在这里插入图片描述
1.我们要筛1~n中的素数,然后先默认他们都是素数,最外层枚举
1~n的所有数,
2.如果它是素数,就加到素数表,
3.对于每一个枚举的i ,枚举素数表里的数,然后素数就会标记自己 i
倍的数不是素数,(素数的倍数不是素数)
4.枚举素数表什么时候停?枚举到i的最小质因子,标记完就可以停
了,保证每个数只被他的最小质因子筛掉。
例如:外层i=15时,素数表里:2,3,5,7,11,13
2
15=30,把30筛掉;3*15=45,把45筛掉,因为15%3==0,退
出里面的循环;
15是被3筛掉的,因为3是15的最小素因子。

sqrt 判别 O( (√N) )
如果x可以表示为两个因子相乘
x=ab 假设a<=b
那么x>=a
a
a<=√x
只需要枚举a<=√x就可以了

求因子和

  1. 一 个 数 A 能 够 表 示 成 多 个 素 数 的 幂 相 乘 的 形 式 。 即A=(a1n1)*(a2n2)(a3n3)…(amnm)。那么A的因子和就
    是 : (1+a1+a12+…a1n1)
    (1+a2+a22+…a2n2)*(1+a3+a3^2
    +…a3n2)*…(1+am+am2+…am^nm)
    2.如果我们把括号拆开看的话,就很容易看出来拆开实际就是
    各个因子相加 比如12的因子和=(1+2+2^2)(1+3)
    =1+2+4+3+6+12

判断一个数,是否是素数。
Input
输入数据有多组(不超过1e5组),每组1个正整数n(1<=n<=1e7)。
Output
如果是素数,输出YES;否则输出NO。
Sample Input
11
15
19
Sample Output
YES
NO
YES

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+1;
const int max1=1e7;
int prime[N];

bool b[N];
int i,j;
int ans=0;
int init(){
    memset(b,1,sizeof(b));
    b[0]=b[1]=0;
  for(i=2;i<=max1;i++)
  {   if(b[i])
      prime[++ans]=i;
      for(j=1;j<=ans&&prime[j]*i<=max1;j++)
      {   b[prime[j]*i]=0;
          if(i%prime[j]==0) break;
      }  }

}
int main()
{  int a;
    init();
while(~scanf("%d",&a))
{if(b[a]==0) printf("NO\n");
    else printf("YES\n");
}return 0;
}

宋朝的女子嫁人时,要考察男子的满意度(满意度=财富值+地位值-婆婆的暴力值)
如果满意度是素数的话,就可以嫁,否则就不答应这门婚事。
Input
第一行是n(1<=n<=50),表示数据的组数;
接下来是n行,每行3个正整数x,y,z(财富值,地位值,暴力值);(1<=x,y,z<=1e14)
Output
如果可以同意这门婚事,输出"yes";
否则输出"no";
Sample Input
2
10 2 1
10 2 2
Sample Output
yes
no

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

const int N=1e7+1;
int prime[N];
int b[N];
int i,j;
int ans=0,max1=1e7;
int init(){
    memset(b,1,sizeof(b));
    b[0]=b[1]=0;
  for(i=2;i<=max1;i++)
  {
      if(b[i])
      prime[++ans]=i;
      for(j=1;j<=ans&&prime[j]*i<=max1;j++)
      {
          b[prime[j]*i]=0;
          if(i%prime[j]==0) break;
      }
  }
     return 0;
}
int  fun(long long  n)
{
    int flag;
    flag=0;
    for(i=1;prime[i]<=sqrt(n*1.0);i++)
    {
        if(n%prime[i]==0) {flag=1;break;}

    }
    if(n==1) flag=1;
    return flag;

}
int main()
{   long long x,y,z;
    int a;
    init();
scanf("%d\n",&a);
   while(a--)
   {
    scanf("%lld %lld %lld",&x,&y,&z);
    if(fun(x+y-z)==1) printf("no\n");
    else printf("yes\n");

    }
    return 0;
}

给定一个范围 n,有 q 个询问,每次输出第 k 小的素数。(2<=n<=4e7,1<=q<=1e4)
Input
第一行包含两个正整数 n,q,分别表示查询的范围和查询的个数。

接下来 q 行每行一个正整数 k,表示查询第 k 小的素数。
Output
输出 q 行,每行一个正整数表示答案。
Sample Input
100 5
1
2
3
4
5
Sample Output
2
3
5
7
11

#include <iostream>
#include <bits/stdc++.h>
#define max1 40000001
using namespace std;


int prime[10000000];
bool b[max1];
int i,j,n,m;
void init(int are)
{  int ans;
    memset(b,1,sizeof(b));
    b[1]=b[0]=0;
    ans=0;
    for(i=2;i<=max1;i++)
    {    if(b[i])

        prime[++ans]=i;

        for(j=1;j<=ans&&prime[j]*i<=max1;j++)
        {
            b[prime[j]*i]=0;
            if(i%prime[j]==0)  break;
        }

    }

}

int main()
{
   int n,q,sum,k;
   scanf("%d %d",&n,&q);
   init(n);
   while(q)
   {
       scanf("%d",&k);

       sum=prime[k];
       printf("%d\n",sum);
       q--;
   }
    return 0;
}

Close
李华再次发现有一种素数很奇特,它依次去掉最高位,剩下的仍为素数,例如:1223,3137等数。后来李华查阅资料知道这样的数叫纯素数。
现在给你一个整数能判断它是不是纯素数呢?
Input
测试数据有多组(不超过1e5组),每组只有一个整数N(1<=N<=1e6)
Output
对于每组数据,若N为纯素数,输出YES,否则输出NO
Sample Input
2
107
13903

Sample Output
YES
YES
NO

#include <iostream>
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
const int maxl=1e7+1;
const int maxx=1e7;
bool isprime[maxl];
int prime[maxl];
int n,x,m;
int init()
{
    memset(isprime,1,sizeof(isprime));
     int sum=0;isprime[0]=0;isprime[1]=0;
     for(int i=2;i<=maxx;i++)
    {if(isprime[i])
         prime[++sum]=i;
         for(int j=1;j<=sum&&i*prime[j]<=maxx;j++)
         {
             isprime[i*prime[j]]=0;
             if(i%prime[j]==0)break;

         }
    }
    return 0;
}
bool ss(int x)
{  int b[10],len=0;
    memset(b,0,sizeof(b));
    while(x)
    {
        b[++len]=x%10;
        x=x/10;
    }
    for(int i=1;i<=len;i++)
    {
        int sum=0;
        for(int j=i;j>=1;j--)
            sum=sum*10+b[j];
        if(!isprime[sum])return 0;
    }
    return 1;
}
int main()
{  init();
    while(~scanf("%d",&n))
    {if(ss(n))printf("YES\n");
     else printf("NO\n");
     }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值