时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给定一个正整数 p 求一个最小的正整数 n,使得 n! 是 p 的倍数
输入描述:
第一行输入一个正整数T表示测试数据组数 接下来T行,每行一个正整数p
输出描述:
输出T行,对于每组测试数据输出满足条件的最小的n
示例1
输入
4
1
2
4
8
输出
1
2
4
4
备注:
T≤103,p≤109
题解:
两个方法:
二分与贪心
在什么条件下n!会是p的倍数呢?
n!的素因子集合包含p的素因子集合,也就是对于每个质因子,阶乘n中的数量大于对应p中的数量
贪心:
暴力做法,从2开始循环质因数,对于每次一个质因数i,看p1当前能分解出多少个,然后再枚举n,看n最小为多少能做到质因数i的数量大于等于p1
代码中有句sum=max(sum,j);什么含义?你想如果我们之前求出n=9包含3的数量满足条件,那枚举5时得到n=10,10的阶乘是包含9的阶乘,也就是10!既满足质因数2也满足3,所以求最大max
代码内也有注释
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
int t,p1,sum=0;
cin>>t;
while(t--)
{
cin>>p1;
sum=0;
for(int i=2;i*i<=p1;++i)
if(p1%i==0)
{
int cnt=0;
while(p1%i==0)
{
p1/=i;
++cnt;
}//当前质因子i在p1中的数量
int tmp=0;
int j;
for(j=i;;j+=i)
{
int n=j;
while(n%i==0)
{
n/=i;
++tmp;
} //记录当前质因数在n中的数量
if(tmp>=cnt) break;//找到一个数,使得他的质因数i的数量多于等于p1
}
sum=max(sum,j);
// cout<<sum<<endl;
}
cout<<max(sum,p1)<<endl;
}
}
二分:
其实就是把方法一中暴力的过程改成更为巧妙的二分过程,先将p1的质因数存入数组prime,然后二分查找,寻找最小的n,满足他的质因数i的数量多于等于p1
代码借鉴其大佬博客写的
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 3;
int prime[maxn], cnt[maxn], len = 0;
//素因子,素因子的个数,数组长度
int judge(int mid) {
for (int i = 1; i <= len; i++)
{
int n = mid
int sum = 0;
while (n)
{
sum += n / prime[i];
n /= prime[i];
}
if (sum < cnt[i]) return 0;//不满足条件就找下一个n
}
return 1;//满足要求
}
int main() {
int T;
cin>>T;
int l,r,sum;
while (T--)
{
int p1;
cin>>p1;
len = 0;
memset(cnt, 0, sizeof cnt);
for (int i = 2; i * i <= p1; i++)
if ( p1 % i==0)
{
prime[++len] = i;
while (p1 % i==0)
{
cnt[len]++;
p1 /= i;
}
}
if (p1 > 1)
{
prime[++len] = p1;
cnt[len]++;
}
//求出素因子及其个数
l = 1, r = 1e9, sum = 0;
while (l <= r) {
int mid = l + r >> 1;
if (judge(mid))
{
r = mid - 1;
sum = mid;
}
else l = mid + 1;
}
//二分查找
printf("%d\n", sum);
}
return 0;
}