素数

个人娱乐专用,先备份,省的以后电脑出问题又没了,是按文件分开的

 

main.cpp

 

#if 0

素数分布 https://baike.baidu.com/item/素数分布/369166?fr=aladdin
素数猜想 
素数测试
算术基本定理 https://baike.baidu.com/item/算术基本定理/10920095?fr=aladdin  高斯公式分解
素数判定
素数因子分解

数论四大定理 威尔逊定理 欧拉定理 孙子定理 费马小定理 https://baike.baidu.com/item/数论四大定理/4751986?fr=aladdin
威尔逊定理 https://baike.baidu.com/item/威尔逊定理 当且仅当p为素数时 (p-1)!=(-1)mod(p)
欧拉定理 https://baike.baidu.com/item/欧拉定理 欧拉函数φ(n) 小于等于n中与n互质的数的个数   a,n互质 a^φ(n)=1 mod(n)
孙子定理 https://baike.baidu.com/item/孙子定理/2841597?fr=aladdin 整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,方程组S有解
费马小定理 https://baike.baidu.com/item/费马小定理 p为质数,ap互质,a^(p-1)=1 mod(p) p整除a a^(p-1)=0mod(p)

素数猜想
伯特兰-切比雪夫定理 https://baike.baidu.com/item/伯特兰-切比雪夫定理/2053704  对n 存在素数p  n<p<2n-2
孪生素数猜想 https://baike.baidu.com/item/孪生素数猜想/4937896?fr=aladdin 存在无穷对孪生素数  孪生素数p,p+2 均为素数
哥德巴赫猜想 https://baike.baidu.com/item/哥德巴赫猜想/72364 任意大于2的数都可以拆成2个素数的和


#endif

//素数分布
#if 0

以黎曼公式为中心,高斯公式为上限
孪生素数 p 和 p-2 均为素数
阴性素数 6N-1 阳性素数 6N+1 起码素数 1 2 3  

 

#endif

//阶乘高斯分解式

#include<stdio.h>
#include"筛选质数.h"
#include"高斯公式计算阶乘分解式.h"
#include"defprime.h"

 

 

int main()
{
    int a[100000] = { 0 };
    isPrime(a);
    factdep(10);
    miller(41);
    return 0;
}

 

 

第二个文件 defprime.cpp

 

#include"defprime.h"
#include<math.h>
#include<stdio.h>


//朴素法
void defprime(int a)
{
    int t = sqrt(a + 0.0);
    for (int i = 2; i <= t; i++)
    {
        if (a%t == 0)
        {
            printf("a isn't a prime\n");
            return;
        }
    }
    printf("a is a prime\n");
    return;
}

#ifdef defprime()
lucas-lehmer

筛选法  同筛选质数,把质数筛选出来,看在不在里面
messiel lehmer


//

#endif

//miller rabin素性测试 概率判断,对更大的数,基于fermat 小定理的逆命题不成立,但是大概率可能成立(伪素数)这篇博客可以  https://www.cnblogs.com/jasonlixuetao/ p/5459623.html  https://www.cnblogs.com/Mathics/p/4028819.html
// 当且p为质数时 a^(p-1)==1 mod p  但逆命题不成立,我们把满足逆命题的称为伪素数,现在就转变成我们判断这个数是不是伪素数
//  比如 2^340==1 mod 341  but 341==11*31 
// miller 的二次检验就是一定程度上解决这个问题,虽然叫随机算法,但只是检验顺序和数目的问题
//  可证如果 a^2=1 mod p  则 a==1 or a==p-1 
//  p-1==2^m*d
// 对伪素数进行检验,取一素数a,算y=a^d 在m次循环里面 算y^2  y==1 x!=p-1
void miller(int n)
{
    int prime[5]={2,3,7,61,24251};
    for(int i=0;i<5;i++)
    {
        int k=prime[i];
        if(istrue(k,n)!=1)
        {
            printf("NO\n");
            return;
        }
    }
    printf("Yes\n");
    return ;
}

int qpow(int k,int t,int n)
{
    int res=1;
    while(t)
    {
        if(t&1)
            res=res*k%n;
        k=k*k%n;
        t=t>>1;
    }
    return res;
}

bool istrue(int k,int n)
{    
    int t=n-1;
    int z=0;
    while(!(t&1))
    {
        z++;
        t=t>>1;
    }
    int x,y;
    x=y=qpow(k,t,n);
    while(z--)
    {
        y=y*y%n;
        if(y==1&&x!=1&&x!=n-1)
            return false;
        x=y;
    }
    return y==1;
}

//miller 模板 别人的
#if 0

/*对应hoj 1356 Prime Judge*/
#include <cstdio>  
#define MT 5  
using namespace std;
typedef long long ll;
int prime[] = { 2, 3, 7, 61, 24251 };
//可以多选底数 2 3 5 7 11 13 31 61 24251 等
ll mulmod(ll a, ll b, ll k)   //快速积
{
    ll re = 0, temp = a;
    while (b) {
        if (b & 1) re = re + temp;
        b >>= 1;
        temp <<= 1;
        //3*7  3*(4+2+1)   3*1+3*2+3*4
    }
    return re%k;
    /*实际上呢,用以上的函数在hoj 1356是会TLE的(mod太多次了...)~应该用下面的方法...*/
    //    return (a*b) % k;//-_-b  
}

ll powermod(ll a, ll b, ll k)  //快速幂
{
    ll re = 1, temp = a;
    while (b) {
        if (b & 1)
            re = mulmod(re, temp, k);
        temp = mulmod(temp, temp, k);
        b >>= 1;
    }
    return re;
}

int TwiceDetect(ll a, ll b, ll k)
{
    int t = 0;
    ll x, y;
    while ((b & 1) == 0) {
        b >>= 1;
        t++;
    }
    /// b = d * 2^t;   b = d;  
    y = x = powermod(a, b, k);/// x = y = a^d % n  
    ///二次探测定理是反向递归的,当然也可以用如下的正向迭代法去测试  
    while (t--) {
        y = mulmod(x, x, k);
        if (y == 1 && x != 1 && x != k - 1)///注意y!=1的时候是不做判断的,即对应  
            return 0;///递归时在某一环节x==p-1的情况,对此x开方则无意义,但是迭代的话不能break,只能ignore并继续.  
        x = y;///继续向高次迭代,那么至少最后一次应该是等于1的(Fermat小定理)  
    }
    return y;
}

bool Miller_Rabin(ll n) {
    ll tmp;
    for (int i = 0; i < MT; i++) {
        tmp = prime[i];
        if (n == prime[i])
            return true;
        if (TwiceDetect(tmp, n - 1, n) != 1)
            return false;
    }
}

int main() {
    ll n;
    while (scanf("%lld", &n) == 1) {
        if ((n > 1) && Miller_Rabin(n)) {
            printf("YES\n");
        }
        else {
            printf("NO\n");
        }
    }
    return 0;
}

#endif

 

//梅森数  2^n - 1 https://baike.baidu.com/item/卢卡斯-莱默检验法/3757240?fr=aladdin
// 方法 lucas-lehmer
void lucas(int n)
{
    //n为第几个梅森数
    int sum=1;
    sum = sum << n;
    sum--;
    int t = 4;
    int i;
    for (i = 2; i < n; i++)
        t = (t*t - 2) % sum;
    if (t%sum==0)
        printf("Yes\n");
    else
        printf("No\n");
    return;
}


// meissel-lehmer 看不懂系列
#if 0

//被打了注释的是 meissel-lehmer算法 用于精确给出n个数里面素数的个数
//打了注释的这个算法我看不懂,而且里面有一些操作我也看不懂,比如没打注释的素数判定
// 需要个大佬大概翻译一下

 

//#include <iostream>
//#include <cstdio>
//#include <algorithm>
//#include <cstring>
//#include <vector>
//#include <cmath>
//#define MAXN 100    // pre-calc max n for phi(m, n)
//#define MAXM 10010 // pre-calc max m for phi(m, n)
//#define MAXP 40000 // max primes counter
//#define MAX 400010    // max prime
//#define chkbit(ar, i) (((ar[(i) >> 6]) & (1 << (((i) >> 1) & 31))))
//#define isprime(x) (( (x) && ((x)&1) && (!chkbit(ar, (x)))) || ((x) == 2))
//
//using namespace std;
//
//
//long long dp[MAXN][MAXM];
//unsigned int ar[(MAX >> 6) + 5] = { 0 };
//int len = 0, primes[MAXP], counter[MAX];
//
//
//
//long long phi(long long m, int n)
//{
//    if (n == 0) return m;
//    if (primes[n - 1] >= m) return 1;
//    if (m < MAXM && n < MAXN) return dp[n][m];
//    return phi(m, n - 1) - phi(m / primes[n - 1], n - 1);
//}
//
//long long Lehmer(long long m) {
//    if (m < MAX) return counter[m];
//
//    long long w, res = 0;
//    int i, a, s, c, x, y;
//    s = sqrt(0.9 + m), y = c = cbrt(0.9 + m);
//    a = counter[y], res = phi(m, a) + a - 1;
//    for (i = a; primes[i] <= s; i++) 
//        res = res - Lehmer(m / primes[i]) + Lehmer(primes[i]) - 1;
//    return res;
//}
//
//int main()
//{
//
//    ar[0] =  1;
//    for (int i = 3; (i * i) < MAX; i = i + 2)
//    {
//        if (!chkbit(ar, i)) {
//            int k = i << 1;
//            for (int j = (i * i); j < MAX; j = j + k)
//                ar[j >> 6] = (ar[j >> 6]) | (1 << ((j >> 1) & 31));
//        }
//    }
//
//    for (int i = 1; i < MAX; i++)
//    {
//        counter[i] = counter[i - 1];
//        if ((i && (i & 1) && (!chkbit(ar, i))) || (i == 2))
//            primes[len++] = i, counter[i]++;
//    }
//
//    for (int n = 0; n < MAXN; n++) {
//        for (int m = 0; m < MAXM; m++) {
//            if (!n) dp[n][m] = m;
//            else dp[n][m] = dp[n - 1][m] - dp[n - 1][m / primes[n - 1]];
//        }
//    }
//    long long int n;
//    while (scanf("%lld", &n) != EOF)
//        printf("%lld\n", Lehmer(n));
//    return 0;
//} 
#define MAX 400010 
#define MAXP 40000
unsigned int ar[(MAX >> 6) + 5] = { 0 };
#define chkbit(ar, i) (((ar[(i) >> 6]) & (1 << (((i) >> 1) & 31))))
#define isprime(x) (( (x) && ((x)&1) && (!chkbit(ar, (x)))) || ((x) == 2))
int counter[MAX], len = 0, primes[MAXP];
#include<stdio.h>
int main()
{
    ar[0] = 1;
    for (int i = 3; (i * i) < MAX; i = i + 2)
    {
        if (!chkbit(ar, i))
        {
            int k = i << 1;
            for (int j = (i * i); j < MAX; j = j + k)
                ar[j >> 6] = (ar[j >> 6]) | (1 << ((j >> 1) & 31));
        }
    }
    int k;
    while ((scanf("%d", &k)) != EOF)
    if (isprime(k))
        printf("YES\n");
}

 

#endif

 

第三个文件高斯公式计算阶乘分解式.cpp

 

#if 0

n!的p的个数 
p(n!) = [n / p] + [n / p ^ 2] + [n/p^3]+....
#endif

#include"高斯公式计算阶乘分解式.h"
#include"筛选质数.h"
#include<stdio.h>
void factdep(int n)
{
    int a[100000];
    isPrime(a);
    for (int i = 0; a[i] < n; i++)
    {
        int t = n / a[i];
        int sum = 0;
        while (t)
        {
            sum = sum + t;
            t = t /a[i];
        }
        if (i == 0)
            printf("(%d ^ %d)", a[i], sum);
        else
            printf("*(%d ^ %d)", a[i], sum);
    }
}


//因子的和  sum=(a^0+a^1+a^2+...+a^m)*(b^0+b^1+...)....

//正因子的个数 k=(m+1)*(n+1)*(....
 

 

第四个文件 筛选质数.cpp

#include"筛选质数.h"

#define N 1000000
bool isVis[N] = { false };

//一般筛选,不考虑这个数是不是素数,把所有他的整数倍的数全划掉
void isPrime(int a[])
{
    int zz = 0;
    for (int i = 2; i < N; i++)
    {
        for (int j = i << 1; j < N; j = j + i)
            isVis[j] = true;
    }
    for (int i = 2; i < N; i++)
    {
        if (!isVis[i])
            a[zz++] = i;
    }
}

#ifdef isPrime()

//因为判定一个数是否为质数,通过比较前sqrt(n)个数是否整除,对于n而言,如果在sqrt(n)范围内有因子,那么n=a*b,a<sqrt(n),b>sqrt(n),既只需要筛选前sqrt(N)个数就行
//第一次优化,不是对所有数都进行倍数的染色,只对那些没有被染色的数(质数)的倍数进行计算
void isPrime(int a[])
{
    int zz = 0;
    for (int i = 2; i < N; i++)
    {
        if (!isVis[i])
        {
            a[zz] = i;
            zz++;
            for (int j = i; j < N; j = j + i)
                isVis[j] = true;
        }
    }
}

//第二次优化,若a=b*c,则 b<sqrt(a)<c 在对质数的倍数染时,只需要对小于sqrt(N)的质数进行操作 
void isPrime(int a[])
{
    int zz = 0;
    for (int i = 2; i < N; i++)
    {
        if (!isVis[i])
        {
            a[zz] = i;
            zz++;
            if(i<sqrt(N))
            for (int j = i; j < N; j = j + i)
                isVis[j] = true;
        }
    }
}

//第三次优化,筛掉偶数,然后筛掉奇数的奇数倍,染色法
void isPrime(int a[])
{
    int zz = 0;
    for(int i=4;i<N;i=i+2)
        isVis[i]=true;
    for(int i=3;i<sqrt(N);i=i+2)
    {
        if(!isVis[i])
        {
            for(int j=i*3;j<N;j=j+i<1)
                isVis[j]=true;
        }
    }
}

//第四次优化染色,记录质数,对质数的倍数进行染色
void isPrime(int a[])
{
    int zz = 1;
    for(int i=4;i<N;i=i+2)
        isVis[i]=true;
    a[0]=2;
    for(int i=3;i<sqrt(N);i=i+2)
    {
        if(!isVis[i])
        {
            a[zz++]=i;
            for(int j=1,k;j<zz&&(k=i*a[j])<N;j++)
            {
                isVis[k]=true;
                if(i%a[j]==0)
                    break;
            }

        }
    }
}
#endif

 

对应三个头文件

defprime.h

#if 0

lucas-lehmer
miller
朴素判断
筛选法  同筛选质数,把质数筛选出来,看在不在里面
messiel lehmer

#endif

#pragma once
void defprime(int n);
bool istrue(int n,int k);
void miller(int n);
int qpow(int i, int j, int k);
void lucas(int n);

 

高斯公式计算阶乘分解式.h

#if 0

#endif

#pragma once
void factdep(int );

 

筛选质数.h

#if 0
自己一直用的的就是筛选法,他的名字叫埃氏和欧式 https://baike.baidu.com/item/筛选法/9393288?fr=aladdin

#endif
#pragma once
void isPrime(int a[]);

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值