- 素数的定义
指在大于1的自然数中,除了1和它自身之外,不能被任何其他自然数整除的数 叫做质数;否则称为合数
(0和1,既不是素数,也不是合数)
素数判定
//暴力法
boolean isPrime(int n){
for(int i=2;i<n;i++){
if(n%i==0){
return false;
}
}
return true;
}
//试除法(暴力法的优化)
//i遍历到n.sqrt()即可判断n是否为素数
/*
可以通过反证法证明:
假设遍历到n.sqrt()仍然无法判断n是否为素数,
则存在自然数a,b;使得n=a*b
同时a,b中必有一数大于n.sqrt();那么另一数一定小于n.sqrt()
较小的数一定会在n.sqrt()前被遍历到。
与假设矛盾
*/
/*
为什么写为i<=n/i ——->假设i是n的因子,那么n/i也是n的因子
故而可以枚举到i<=n/i
*/
boolean isPrime(int n){
for(int i=2;i<=n/i;i++){
if(n%i==0){
return false;
}
}
return true;
}
素数筛(埃氏筛)
理解:素数的倍数一定是合数
基本思路:给定范围n,从2开始,将每个素数的倍数标记为合数。那么一个数没有被之前的数标记,它一定是素数
public class PrimeSieve {
public static void main(String[] args) {
int n = 100; // 要筛选的范围
boolean[] isPrime = new boolean[n + 1];
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= n; i++) {
if (isPrime[i]) {
for (int j = i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}
System.out.println("小于等于" + n + "的素数有:");
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
System.out.print(i + " ");
}
}
}
}
唯一分解定理
任何一个大于1的整数n都可以分解成若干个素因数的连乘积,如果不计各个素因数的顺序,那么这种分解是唯一的
-
唯一分解定理公式:(某个质因子(p)的个数)
-
举个例子更容易理解:
eg.求n!中 5的个数--》也就是求n!中末尾为0的个数
代码如下:
public static int check(int n) {
int count = 0;
while (n > 0) {
n /= 5;
count += n;
}
return count;
}
不是求n!中5的个数吗?为什么传参只传了n?
因为在计算n!时,是求123*…*n。也就是统计1到n中所有数的因子5的个数之和
在计算n!中因子5的个数时,一些数会贡献因子5
而n中包含了这些数贡献的因子5
所以计算n!中5的个数的总和,其实就是n中包含5的个数
例如:
15/5 = 3 //15!中就包含了3个5
25/5 = 5 ; 5/5 =1 sum=5+1--->//25!中就有6个5
蓝桥真题:求阶乘
问题描述:满足N!的末尾恰好有K个0的最小N是多少?如果不存在这样的N 输出-1
//还是有超时的可能
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
long k = scan.nextLong();
//有k个0,就是有k个5
long l = 1L;
long r = Long.MAX_VALUE;
//二分法
while(l<r) {
long mid = (l+r)/2;
if(check(mid) >= k) r = mid;
else if(check(mid)<k) l = mid+1;
}
if(check(r) == k) {
System.out.println(r);
}else {
System.out.println(-1);
}
}
public static long check(long mid) {
long count = 0;
//计算n中有多少个5--->唯一分解定理的质因子个数公式---》n!中有多少个5
while(mid!=0) {
count+=mid/5;
mid = mid/5;
}
return count;
}
}
eg. 100=2*2*5*5
c++
/**
* 功能:分解质数因数
* @param x 待分解的数字
* @param a 分解后的数组
* @return 数组的最后一个元素下标
*/
int Decomposition(int x, int a[]) {
int cnt = 0;
for (int i = 2; i <= x / i; i++)
while (x % i == 0) {
x /= i;
a[++cnt] = i;
}
if (x > 1)a[++cnt] = x;
return cnt;
}
const int N = 110;
int a[N];
//用法:
int cnt = Decomposition(12, a);
for (int i = 1; i <= cnt; i++) cout << a[i] << " ";
约数定理
n可以分解质因数:n=p1a1*p2a2*…*pk^ak (pk是素数 ak是pk的指数)
则,p1^a1 的约数有:p10,p11,….,p1^a1,共(a1+1)个
同理,p2^a2 的约数有(a2+1)个….pk^ak约数个数有(ak+1)个
参考资料
- 【约数定理(约数个数定理,约束和定理) - 优快云 App】https://blog.youkuaiyun.com/piaocoder/article/details/47954385?utm_source=app&app_version=6.3.0
- 【大整数分解——Pollard Rho算法 - 优快云 App】http://t.csdnimg.cn/ID2BFv