思路清奇的一道题,也覆盖了很多知识点
记录一下
题目
描述
给定n,a求最大的k,使n!可以被ak整除但不能被a(k+1)整除。
输入描述:
两个整数n(2<=n<=1000),a(2<=a<=1000)
输出描述:
一个整数.
输入样例
6 10
输出样例
1
思路
参考https://blog.csdn.net/csyifanZhang/article/details/105754286
其中对n!分解质因数的方法很巧妙
由于n范围较大,不能直接求出n!再暴力求解,所以换一个思路
n!能够整除ak,说明n!包含ak的所在质因数,那么我们首先就需要将a和n!分解质因数
求出最大k,对于a与n!的公共质因数{x1, x2,…,xi},
k
i
=
(
i
n
t
)
l
o
g
x
i
(
n
!
分
解
结
果
中
x
i
的
次
数
)
k_i=(int)log_{x_i}(n!分解结果中x_i的次数)
ki=(int)logxi(n!分解结果中xi的次数),取ki中找到最小值
代码
#include<bits/stdc++.h>
using namespace std;
int n,a,cnt;
int primes[1001]; //存储1-1000的所有素数
int isPrime[1001]; //isPrime[i],i是否是素数
unordered_map<int, int> ma,m;//ma是a的质因数--质因数对应的次数
//m是n!的质因数--质因数对应的次数
/* 对x分解质因数 */
void primeFac(int x){
for(int i = 0;i<cnt && primes[i] <= a;++i){
while(a%primes[i]==0){
++ma[primes[i]];
a /= primes[i];
}
}
}
/* 对x!分解质因数 */
void primeFacN(int x){
for(int i = 0;i<cnt && primes[i]<x;++i){
int t = primes[i];
while(t<x){
m[primes[i]] += x/t;
t*=primes[i];
}
}
}
int main(){
cin>>n>>a;
//埃及筛法求1-1000中的素数,存入primes
memset(isPrime,1,sizeof(isPrime));
isPrime[1] = 0;
for(int i = 2;i<1001;++i)
if(isPrime[i]){
for(int j = i*2;j<1001;j += i)
isPrime[j] = 0;
}
for (int i = 2; i < 1001; i++)
if (isPrime[i])
primes[cnt++] = i;
//分解质因数
primeFac(a);
primeFacN(n);
int res = 1<<30;
for(unordered_map<int,int>::iterator it = ma.begin();it!=ma.end();++it){
int nn = it->first, num = it->second;
if(num>m[nn]){
res = 0; break;
}
res = min(m[nn]/num,res);
}
cout<<res;
return 0;
}