约数

约数

唯一分解定理

图片描述

n的质因数个数----唯一分解定理
public static int num(long n){   
    int ans = 0;    
    for(int i=2;i<n/i;i++){        
        while(n%i==0){            
            ans++;              
            n/=i;        
        }    
    }    
    if(n>1)        
        ans++;    
    return ans;
}
n的约数个数----唯一分解定理
public static int num(int n){
    int cnt = 1;//乘法初始值为1
    int bak = n;//备份n
    for(int i=2;i*i<bak;i++){
        int sum = 0;
        while(bak%i==0){
            sum++;
            bak = bak / i;
        }
        cnt = cnt * (sum + 1);
    }
    if(bak>1) cnt*=2;
    return cnt;
}
求n!的约数个数----唯一分解定理
public static long num(int n){
    int[] prime = new int[n+1];//prime[i]表示素数i这个因子出现的次数
    for(int i=2;i<=n;i++){
        int bak = i;
        for(int j=2;j*j<bak;j++){
            int sum = 0;
            while(bak%j==0){
                prime[j]++;
                bak = bak / j;
            }
    	}
    	if(bak>1) prime[bak]++;
    }
    long ans = 1;
    for(int i=2;i<=n;i++){
        if(prime[i]>1)
            ans = ans * (prime[i]+1);
    }
    return ans;	
}
例题:数数

题目链接:数数 - 蓝桥云课 (lanqiao.cn)

图片描述

​ 思路:将这个区间中的每一个数都根据唯一分解定理进行拆分,统计有多少个数的拆分结果为 12 12 12

import java.util.Scanner;

public class 数数 {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int ans = 0;
		for(int i=2333333;i<=23333333;i++)
			if(num(i)==12)
				ans++;
		System.out.println(ans);
	}
	static int num(int n) {
		int ans = 0;
		for(int i=2;i<n/i;i++) {
			while(n%i==0) {
				n/=i;
				ans++;
			}
		}
		if(n>1)
			ans++;
		return ans;
	}
}

例题:求阶乘

题目链接:求阶乘 - 蓝桥云课 (lanqiao.cn)

图片描述

​ 思路:

​ 1.根据唯一分解定理可知:每一个数都可以写为 n n n 个素数的乘积;

​ 2.如果一个数的结尾有 0 0 0 的存在,那么这个数分解后一定有 2 2 2 5 5 5 (素数中,只有 2 × 5 2 \times 5 2×5 才能使结尾产生 0 0 0 );

​ 3.从 1 1 1 ~ N N N ,将每一个数都分解后, 2 2 2 的数量一定比 5 5 5 多( 2 2 2 每隔两个数就会最少出现一个, 5 5 5 每隔 5 5 5 个数,最少出现一个),那么, N ! N! N! 末尾 0 0 0 的数量,就是将 1 1 1 ~ N N N 中每个数分解后, 5 5 5 的数量;

​ 4.如果用一个循环从 5 5 5 开始,每次 + 5 +5 +5 ,判断这些数可以拆分出几个 5 5 5 ,然后去找结尾有 k k k 0 0 0 的最小的 N N N 是多少,这个方法结果正确,但是时间复杂度会比较高,所以借助二分,去找到结尾有 k k k 0 0 0 的最小的 N N N 是多少;

​ 5.用二分去查找,就必须做到:已知 N N N ,求出 1 1 1 ~ N N N 中可以拆分出多少个 5 5 5 ,以 125 125 125 为例,因为每五个数才拆分出 5 5 5 ,所以,如果 1 1 1~ 125 125 125 都只拆一个 5 5 5 ,则可以拆分出 125 / 5 125 / 5 125/5 25 25 25 5 5 5 ,拆分后的结果为 1 1 1 ~ 25 25 25 ,然后继续拆分 5 5 5 1 1 1 ~ 25 25 25 可以拆分出 25 / 5 25 / 5 25/5 5 5 5 ,拆分后结果为 1 1 1 ~ 5 5 5 1 1 1 ~ 5 5 5 可以拆分出 5 5 5 / 5 5 5 5 5 5 ,最后剩余 1 1 1 1 1 1 无法继续拆分出 5 5 5 ,所以 125 125 125 可以拆分出 25 + 5 + 1 = 31 25 + 5 + 1 = 31 25+5+1=31 5 5 5

​ 6.二分:如果 m i d mid mid 拆分出的 5 5 5 的数量 ≥ k \ge k k,那么可以 r i g h t = m i d right = mid right=mid ,反之 l e f t = m i d + 1 left = mid + 1 left=mid+1,二分结果后,还需要判断它是否确实能拆分出 k k k 5 5 5 ,因为存在一个 N ! N! N! 能恰好末尾有 k k k 0 0 0

import java.util.Scanner;

public class 求阶乘 {
	public static long find(long x) {//求x能拆分出多少个5
		long res = 0;
		while(x != 0) {
			res = res + x / 5;
			x/=5;
		}
		return res;
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long k = sc.nextLong();
		long l = 0,r = 100000;//防止溢出
		while(l < r) {
			long mid = (l + r) / 2;
			if(k <= find(mid)) {
				r = mid;
			}else {
				l = mid + 1;
			}
		}
		if(find(r) != k) {//确保有解
			System.out.println(-1);
		}else {
			System.out.println(r);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值