【説明する】素数

 素数栗子:


素数相关知识:

素数概念:

最大公约数只有1和它本身的数叫做质数(素数)

素数小性质:

1.大于一的整数必有素因数。

2.设p是素数,n是任意一个整数

能够推出p|n,(p,n)=1;

3.设p是素数,a,b为整数,若p|ab,则ab中至少有一个能被p整除

4.素数有无穷多个证明

(素数与整数之间的关系:1整除2互素)

假定正整数中只有有限个素数

设p1,p2……pk为从小到大排列起来的数

且N=p1*p2*……pk

 设M=N+1

如果M为素数,那么M要大于p1,p2……pk,

所以它不在那些假设的素数集合中

若M为合数

∵任何一个合数都可以分解为几个素数的积,而N和M的最大公约数是1

∴p不可能被p1,p2……pk整除

∴该合数分解得到的素因数肯定不在假设的素数集合中。

∴无论M是素数还是合数,都意味着在假设的有限个素数之外还存在着其他素数。

∴原先的假设不成立,也就是说,素数有无穷多个。

5. 质数的个数公式 style='orphans: auto;text-align:start;widows: auto;-webkit-text-stroke-width: 0px; word-spacing:0px' align=absmiddle title="" v:shapes="_x0000_i1025"> 是不减函数

6. 若n为正整数,在 align=absmiddle title="" v:shapes="_x0000_i1026"> 到  align=absmiddle title="" v:shapes="_x0000_i1027"> 之间至少有一个质数

7. 若n为大于或等于2的正整数,在n到 之间至少有一个质数

8. 若质数p为不超过n( )的最大质数,则

9. 所有大于10的质数中,个位数只有1,3,7,9


至今为止,没有任何人发现素数的分布规律,也没有人能用一个公式计算出所有的素数。

关于素数的很多的有趣的性质或者科学家的努力

1.高斯猜测,n以内的素数个数大约与n/ln(n)相当,或者说,当n很大时,两者数量级相同。这就是著名的素数定理。  
2.十七世纪费马猜测,2的2^n次方+1,n=0,1,2…时是素数,这样的数叫费马素数,可惜当n=5时,2^32+1就不是素数,
  至今也没有找到第六个费马素数。
3.18世纪发现的最大素数是2^31-1,19世纪发现的最大素数是2^127-1,20世纪末人类已知的最大素数是2^859433-1,用十进制表示,这是一个258715位的数字。
4.孪生素数猜想:差为2的素数有无穷多对。目前知道的最大的孪生素数是1159142985×2^2304-1和1159142985×2^2304+1。
5. 歌德巴赫猜想:大于2的所有偶数均是两个素数的和,大于5的所有奇数均是三个素数之和。其中第二个猜想是第一个的自然推论,因此歌德巴赫猜想又被称为1+ 1问题。我国数学家陈景润证明了1+2,即所有大于2的偶数都是一个素数和只有两个素数因数的合数的和。国际上称为陈氏定理。


合数概念: 

合数是除了1和它本身以外 还能被其他的正整数整除的正整数。 
除2之外的偶数都是合数。(除0以外) 
合数又名合成数,是满足以下任一(等价)条件的正整数,

  性质 :

  1.是两个大于 1 的整数之乘积; 
  2.拥有某大于 1 而小于自身的因数(因子); 
  3.拥有至少三个因数(因子); 
  4.不是 1 也不是素数(质数); 
  5.有至少一个素因子的非素数。


筛法求素数:

若m是合数,p是m的最小正约数,所以p<=sqrt(m);

证明:∵m为p的约数,

那么我们可以设 m=p*q;

          又∵p是最小的正约数;

          ∴q>=p;//p不等于=q且p是最小的正约数;

          ∴p*p<p*q=m;

          ∴p<=sqrt(m);

在1到m之间,运用筛法求素数:(floor为向下取整)

即在1到m中,把2到floor(sqrt(m))中素数的倍数(倍数>1)和1都去掉,其余的数就是素数;

但是有一点要注意的是:

运用筛法,只能求1m之间的素数,但是不能求nm之间的素数

基本判断思路:

①在一般领域,对正整数n,如果用2到sqrt(n)之间的所有整数去除,均无法整除,则n为质数。

②质数大于等于2

③不能被它本身和1以外的数整除


给出代码:

我自己胡乱搞的方法:

int pd(int x)
{
    if(x==2||x==3) return 1;
    if(x%2==0 || x==1) return 0;
    int j=3;
    while(j<=sqrt(x)&&x%j!=0) j+=2;
    if(x%j==0) return 0;
    else return 1;
}

普通方法直接来判断是否为素数:

#include <iostream>
#include <cmath>
using namespace std;

int main() {
    int b;
    while(cin>>b) {
        if(b<0) {
            cout<<"It's can't a prime! Because it's tan 90 ^_^, Don't ask me why!"<<endl;
            continue;
        }
        if(b<=1 && b>=0) {
            cout<<"It's not a prime! Because it's rules!"<<endl;
            continue;
        }
        bool ok=true;
        for(int i=2; i<=sqrt(b); ++i) {
            if(b%i==0) {
                ok=false;
                cout<<"It's not a prime, because of the smallest number "<<i<<endl;
                break;
            }
        }
        if(ok)
            cout<<"Yes, this is a prime!"<<endl;
    }
    return 0;
}

经典的Eraosthenes筛法:

#include <iostream>
#include <cmath>
using namespace std;

const int Maxn = 10000001;
int n,cnt; 
int prime[Maxn];
bool notprime[Maxn];

void Eraosthenes_pre() {
    for(int i=2; i<sqrt(n); ++i) {
        if(notprime[i])
            continue;
        for(int j=i; i*j<n; ++j)
            notprime[i*j]=true;
    }
    for(int i=2; i<n; ++i)
        if(!notprime[i])
            prime[cnt++]=i;
}

int main() {
    cin>>n;
    Eraosthenes_pre();
    for(int i=0; i<cnt; ++i) 
        cout<<prime[i]<<endl;
    return 0;
}

但是Eraosthenes筛法的速度并不快,原因在于对于一个合数,这种方法会重复的标记。

一种线性筛素数的方法有效的解决了这一点。

线性筛代码如下:

void get_prime() {
    notprime[0]=notprime[1]=true;
    for(int i=2; i<=n; ++i) {
        if(!notprime[i])
            prime[++cnt]=i;
        for(int j=1; j<=cnt && i*prime[j]<=n; ++j) {
            notprime[i*prime[j]]=true;
            if(i%prime[j]==0)
                break;
        }
    }
}

小知识点:

唯一分解定理定义:

任意大于1的整数,若不计因子排列顺序,都可以被唯一分解为素数(不会是只有2个素数的乘积,可能是多个)的乘积;

n=p1α1×p2α2×……×psαs

pi(i=1,2,……,s)为两两互不相等的素数,

αi(i=1,2,……,s)为正整数;

举个栗子:56=2^3*7;

C++代码实现:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 10086

using namespace std;

bool ss[maxn];
int css[maxn],num;
int ans[maxn],times[maxn],cnt;
int n;

void zss()
{
    memset(ss,1,sizeof(ss));
    ss[1]=0;
    for(int i=2;i<=maxn;i++)
        if(ss[i])
        {
            css[++num]=i;
            for(int j=2;j*i<=maxn;j++)ss[i*j]=0;
        }
}
int main()
{
    scanf("%d",&n);
    printf("%d=",n);
    zss();
    int k=1;
    while(n!=1&&k<=num)
    {
        int p=0;
        if(n%css[k]==0)
        {
            while(n%css[k]==0)
            {
                n/=css[k];
                p++;
            }
            ans[++cnt]=css[k];
            times[cnt]=p;
        }
        k++;
    }
    for(int i=1;i<cnt;i++)
        if(times[i]!=1) printf("%d^%d*",ans[i],times[i]);
        else printf("%d*",ans[i]);
    if(times[cnt]==1) printf("%d",ans[cnt]);
    else printf("%d^%d",ans[cnt],times[cnt]);
    return 0;
}
View Code

例题 

例题1:质因数分解

总时间限制:
  1000ms
内存限制: 
  65536kB
描述

已知正整数 n 是两个不同的质数的乘积,试求出较大的那个质数。

输入
输入只有一行,包含一个正整数 n。

对于60%的数据,6 ≤ n ≤ 1000。
对于100%的数据,6 ≤ n ≤ 2*10^9。
输出
输出只有一行,包含一个正整数 p,即较大的那个质数。
样例输入
21
样例输出
    7
思路:

  根据唯一分解定理,若此题有答案,则输入数据满足有且只有一组质数相乘=n

  所以,i从2循环到根号n,如果n%i==0,则n/i为答案

  也就是说,n=质数a*质数b,n没有其他的分解

证明:

  假设还有另外一组分解c*d

  那么c*d分解质因数的结果与a*b相同

  又因为a、b是质数

  所以a*b分解质因数=a*b

  所以c=a,d=b

  即只有一种分解

 c++代码实现:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

int pd(int x) {
    if(x==2 || x==3) return 1;
    if(x%2==0 || x==1) return 0;
    int j=3;
    while(j<=sqrt(x) && x%j!=0) j+=2;
    if(x%j==0) return 0;
    else return 1;
}

int main() {
    int n;
    scanf("%d",&n);
    int t=sqrt(n); //i最大的范围
    for(int i=2; i<=t; i++) { //因为1不是质数,所以循环从2开始进行
        if(n%i==0) { //如果找到了能够进行整除的i
            //又因为样例说一定满足n 是两个不同的质数的乘积,所以直接输出另外一个数就行
            //if(pd(i)) {//所以由上得:不需要判断第一个数是否能够被模 ,即满足唯一分解定理
                printf("%d",n/i);
                return 0;
//            }
        }
    }
    return 0;
}
View Code

例题2:第n小质数

总时间限制:
   1000ms
内存限制: 
  65536kB
描述

输入一个正整数n,求第n小的质数。

输入
一个不超过10000的正整数n。
输出
第n小的质数。
样例输入
10
样例输出
    29
坑点:
一定要注意范围!!!!范围!!!!范围!!!!
c++代码实现
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
/*
#define M 10001这里!!数组开的不能太小!!!
上面跟下面选取一个进行改正
*/
#define M 10002
using namespace std;

struct Q {
    int top;
    Q() { top=0; }
    int s[M];
    void jiajia() { top++; }
    int add(int x) { s[top]=x; }
} q;

int pd(int x) {
    if(x==2 || x==3) return 1;
    if(x%2==0 || x==1) return 0;
    int j=3;
    while(j<=sqrt(x) && x%j!=0) j+=2;
    if(x%j==0) return 0;
    else return 1;
}

void Q_work() {
    q.jiajia();
    q.add(2);
    for(int i=3;; i++) {
        if(pd(i)) {
            q.jiajia();
            q.add(i);
        }
        if(q.top>10000) //因为结束条件是q.top>10000所以需要使用到10001个,所以数组需要开到10002
            //if(q.top>=10000) 或者上面不改,改这里
            break;
    }
}

int main() {
    int n;
    scanf("%d",&n);
    Q_work();
    printf("%d",q.s[n]);
    return 0;
}
View Code

例题3:1530 大质数 

题目描述 Description

小明因为没做作业而被数学老师罚站,之后数学老师要他回家把第n个质数找出来。(1<=n<=100000)

老师随机写了几个数,交给了小明。小明百度找了很久,都没能解决。现在交给聪明的你。请你帮忙!

—————————————————————————————————————————————

简单描述:把第n个质数找出来。

输入描述 Input Description

一个正整数n。

(1<=n<=100000)

输出描述 Output Description

第n个质数。

(第1个质数为2,第2个质数为3。)

样例输入 Sample Input

样例1

2

样例2

65

样例3

20133

样例输出 Sample Output

样例1

3

样例2

313

样例3

226381

c++代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

int pd(int x) {
    if(x==2 || x==3) return 1;
    if(x%2==0 || x==1) return 0;
    int j=3;
    while(j<=sqrt(x)&&x%j!=0) j+=2;
    if(x%j==0) return 0;
    else return 1;
}

int n,ans,js;
void Q_work() {
    if(n==1) {
        cout<<"2";
        return;
    }
    js=1;
    for(int i=2; js!=n; i++) {
        if(pd(i)) {
            ans=i;
            js++;
        }
    }
    printf("%d",ans);
}

int main() {
    scanf("%d",&n);
    Q_work();
    return 0;
}
View Code 1
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define M 100001
using namespace std;

struct Q {
    int top;
    Q() {
        top=0;
    }
    int s[M];
    void jiajia() {
        top++;
    }
    int add(int x) {
        s[top]=x;
    }
} q;

int pd(int x) {
    if(x==2 || x==3) return 1;
    if(x%2==0 || x==1) return 0;
    int j=3;
    while(j<=sqrt(x)&&x%j!=0) j+=2;
    if(x%j==0) return 0;
    else return 1;
}

int n;
void Q_work() {
    q.jiajia();
    q.add(2);
    for(int i=3;; i++) {
        if(pd(i)) {
            q.jiajia();
            q.add(i);
        }
        if(q.top>=n)
            break;
    }
}

int main() {
    scanf("%d",&n);
    Q_work();
    printf("%d",q.s[n]);
    return 0;
}
View Code 2

例题4:判决素数个数

总时间限制: 
1000ms
内存限制: 
65536kB
描述

输入两个整数X和Y,输出两者之间的素数个数(包括X和Y)。

输入
两个整数X和Y(1 <= X,Y <= 105)。
输出
输出一个整数,表示X,Y之间的素数个数(包括X和Y)。
样例输入
  1 100
样例输出
  25
思路:
  这道题有个大坑!!!!给的数据有可能x>y!!!!
c++代码实现
#include<iostream>
#include<cstdio> 
using namespace std;

int main() {
    int x,y,n,t;
    cin>>x>>y;
    if(x>y) {//进行交换,使得小数在前
        t=x;x=y;y=t;
    }
    for(int i=x; i<=y; i++) {
        int p=1; //是否为素数
        if(i==1) //特判1不是素数
            p=0;
        for(int j=2; j*j<=i; j++) //筛法求素数
            if(i%j==0) {
                p=0;
                break;
            }
        n+=p; //统计个数
    }
    cout<<n;
    return 0;
}
View Code

例题5:codevs 1702 素数判定2

题目描述 Description

一个数,他是素数么?

设他为P满足(P<=263-1)

输入描述 Input Description

P

输出描述 Output Description

Yes|No

样例输入 Sample Input

2

样例输出 Sample Output

Yes

数据范围及提示 Data Size & Hint

算法导论——数论那一节
注意Carmichael Number

c++代码实现

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

typedef long long ll;
int num[8] = {2,3,5,7,11,13,17,19};
int cnt=8;

ll mod_mul(ll a,ll b,ll mod) { // get the answer to a*b%n
    ll res=0;
    while(b) {
        if (b&1) res=(res+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return res;
}
ll mod_exp(ll a,ll b,ll n) { // get the ans to a^b%n
    ll res=1;
    while(b) {
        if (b&1) res=mod_mul(res,a,n);
        a=mod_mul(a,a,n);
        b>>=1;
    }
    return res;
}

bool check(ll n) {
    if(n==2) return 1;
    for(int i=0; i<8; i++) if(n==num[i]) return 1;
    if(n==1 || (!(n&1))) return 0;
    int k=0;
    ll x,u=n-1,pre;
    while(!(u&1)) {
        k++;
        u>>=1;
    }
    for(int i=0; i<cnt; i++) {
        x=num[i];
        x=mod_exp(x,u,n); // 费马小定理 a^(p-1)%p==1;
        pre=x;
        for(int j=0; j<k; j++) {
            x=mod_mul(x,x,n);  // add delete
            if(x==1 && pre!=1 && pre!=n-1) return 0; // if last pre == 1 then x must == 1 else x==p-1;
            pre=x; // second check the x of x^2%p=1 if 1 or p-1;
        }
        if(x!=1) return 0;
    }
    return 1;
}

int main() {
    ll n;
    cin>>n;
    if(check(n)) cout<<"Yes";
    else cout<<"No";
    return 0;
}
View Code

例题6:孪生素数2

题目描述 Description

如m=100,n=6

则将输出100以内的所有相差6的孪生素数:如,

5 11

7 13

....

83 89

请按此规律输出数与数之间用半角空格区分,每一对一行.

输入描述 Input Description

第一行输入一个整数数m为一个范围(如100)

第二行输入一个整数k为目标孪生素数的公差(如6)

输出描述 Output Description

每行输出一对,最后一行输出:Total Is:?(?表示总共有几对这样的数,如果不存在则输出Total Is:0)

样例输入 Sample Input

例如1:

50 2

例如2:

100 90

例如3:

200 199

样例输出 Sample Output

例如1:

3 5
5 7
11 13
17 19
29 31
41 43
Total Is:6

例如2:

7 97
Total Is:1

例如3:

Total Is:0

数据范围及提示 Data Size & Hint

m<=5000

c++代码实现

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

const int M = 5005;
int n,k,js;
int vis[M];

int pd(int x) {
    if(!vis[x]) return 1;
    else return 0;
}
void works(int end) {
    vis[0]=vis[1]=1;
    for(int i=2; i<=sqrt(end+0.5); i++)
        if(vis[i]==0)
            for(int j=i*2; j<=end; j+=i)
                vis[j]=1;
}

int main() {
    scanf("%d%d",&n,&k);
    works(n);
    for(int i=1; i<=n; i++)
        if(i+k<=n && pd(i) && pd(i+k)) {
            cout<<i<<" "<<i+k<<endl;
            js++;
        }
    cout<<"Total Is:"<<js;
    return 0;
}
View Code

例题7:1031 质数环

题目描述 Description

一个大小为N(N<=17)的质数环是由1到N共N个自然数组成的一个数环,数环上每两个相邻的数字之和为质数。如下图是一个大小为6的质数环。为了方便描述,规定数环上的第一个数字总是1。如下图可用1 4 3 2 5 6来描述。若两个质数环,数字排列顺序相同则视为本质相同。现在要求你求出所有本质不同的数环。

输入描述 Input Description

只有一个数N,表示需求的质数环的大小。如:

输出描述 Output Description

每一行描述一个数环,如果有多组解,按照字典序从小到大输出。如:

样例输入 Sample Input

6

样例输出 Sample Output

1 4 3 2 5 6

1 6 5 2 3 4

数据范围及提示 Data Size & Hint
n<=17
c++代码实现
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>

using namespace std;

bool b[18],vis[999];
int n,a[18];

void works(int end) {
    vis[0]=vis[1]=1;
    for(int i=2; i<=sqrt(end+0.5); i++)
        if(vis[i]==0)
            for(int j=i*2; j<=end; j+=i)
                vis[j]=1;
}

bool pd(int x,int y) { //判断和是否为素数;
    int i=x+y;//代表和
    if(!vis[i]) return 1;
    else return 0;
}

int print() { //输出;
    for(int j=1; j<=n; j++) cout<<a[j]<<" ";
    cout<<endl;
}

int search(int t) {
    for(int i=2; i<=n; i++) {
        //判断该数是否可用 以及 该数与前一个数是否构成素数 
        //!b[i]是说b[i]没有被使用过
        if((!b[i]) && pd(a[t-1],i)) { 
            a[t]=i;
            b[i]=1; //将使用过的赋值为1;
            if(t==n && pd(a[n],1)) print();
            else search(t+1);
            b[i]=0;//还原;
        }
    }
}

int main() {
    cin>>n;
    a[1]=b[1]=1;
    if(n%2==1) {
        cout<<endl;
        return 0;
    } else {
        works(60); //第十七个素数为59
        search(2);
    }
    return 0;
}
View Code

例题8: luogu P1217 [USACO1.5]回文质数 Prime Palindromes

题目见链接

c++代码实现

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

const int N = 1e8 + 1;
const int M = 6e7;
int a,b;

int pd(int x) {
    if(x==2 || x==3) return 1;
    if(x%2==0 || x==1) return 0;
    int j=3;
    while(j<=sqrt(x) && x%j!=0) j+=2;
    if(x%j==0) return 0;
    else return 1;
}

void get_hui() {
    int num,aa=a;
    while(aa<10) {
        if(pd(aa) && aa>=a) printf("%d\n",aa);
        aa++;
    }
    for(int i=1; i<=9; i+=2) {
        num=i*10+i;
        if(num>b) return;
        if(num>=a && pd(num)) printf("%d\n",num);
    }
    for(int i=1; i<=9; i+=2) {
        for(int j=0; j<=9; j++) {
            num=i*100+j*10+i;
            if(num>b) return;
            if(num>=a && pd(num)) printf("%d\n",num);
        }
    }
    for(int i=1; i<=9; i+=2) {
        for(int j=0; j<=9; j++) {
            num=i*1000+j*100+j*10+i;
            if(num>b) return;
            if(num>=a && pd(num)) printf("%d\n",num);
        }
    }
    for(int i=1; i<=9; i+=2) {
        for(int j=0; j<=9; j++) {
            for(int k=0; k<=9; k++) {
                num=i*10000+j*1000+k*100+j*10+i;
                if(num>b) return;
                if(num>=a && pd(num)) printf("%d\n",num);
            }
        }
    }
    for(int i=1; i<=9; i+=2) {
        for(int j=0; j<=9; j++) {
            for(int k=0; k<=9; k++) {
                num=i*100000+j*10000+k*1000+k*100+j*10+i;
                if(num>b) return;
                if(num>=a && pd(num)) printf("%d\n",num);
            }
        }
    }
    for(int i=1; i<=9; i+=2) {
        for(int j=0; j<=9; j++) {
            for(int k=0; k<=9; k++) {
                for(int w=0; w<=9; w++) {
                    num=i*1000000+j*100000+k*10000+w*1000+k*100+j*10+i;
                    if(num>b) return;
                    if(num>=a && pd(num)) printf("%d\n",num);
                }
            }
        }
    }
    for(int i=1; i<=9; i+=2) {
        for(int j=0; j<=9; j++) {
            for(int k=0; k<=9; k++) {
                for(int w=0; w<=9; w++) {
                    num=i*10000000+j*1000000+k*100000+w*10000+w*1000+k*100+j*10+i;
                    if(num>b) return;
                    if(num>=a && pd(num)) printf("%d\n",num);
                }
            }
        }
    }
}

int main() {
    scanf("%d%d",&a,&b);
    get_hui();
    return 0;
}
View Code

例题9: luogu P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib

题目见链接

c++代码实现

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int pd(int x) {
    if(x==2 || x==3) return 1;
    if(x%2==0 || x==1) return 0;
    int j=3;
    while(j<=sqrt(x) && x%j!=0) j+=2;
    if(x%j==0) return 0;
    else return 1;
}

int len;
void work(int pre,int now) {
    for(int i=1; i<=9; i++)
        if(pd(pre*10+i)) {
            if(now==len) printf("%d\n",pre*10+i);
            else work(pre*10+i,now+1);
        }
}

int main() {
    scanf("%d",&len);
    work(0,1);
    return 0;
}
View Code

End.

posted @ 2017-06-22 15:23  夜雨声不烦  阅读(826)  评论(0编辑  收藏  举报