约数
唯一分解定理
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;
}
例题:数数
思路:将这个区间中的每一个数都根据唯一分解定理进行拆分,统计有多少个数的拆分结果为 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;
}
}
例题:求阶乘
思路:
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);
}
}
}