个人娱乐专用,先备份,省的以后电脑出问题又没了,是按文件分开的
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[]);