思路:题目的意思我就不再多说了 我们来介绍一下用二分法如何解
对于二分法,我们要先明确将哪个量进行二分,然后再确定该变量的左右范围。
对于本题,我们将我们要求的值,也就是对n进行二分,接下来,我来介绍一下具体的思路:
首先,我们将输入的p进行质因数分解,为什么?
因为满足条件的n!可能十分大,如果不对它进行质因数分解的话,那你就得算出n!,被T风险不说,还可能爆掉。
如何理解上面这句话 比如 p=8, 分解质因数的话 发现8=23 即质因数为2 如果求一个最小的n!使得为8的倍数 ,就可以理解为 n! 中能至少分解出3个2 所以由此我们展开二分的思路
来看这个代码就是进行质因数分解的,我们的目的是统计出它的质因数(用primes数组)和对应的质因数的个数(用num数组),如:
primes[1]表示的是第一个质因数,num[1]表示第一个质因数的个数。其实可以用容器的 unordered_map<int,int>的,但考虑到蓝桥杯不能使用 所以我们尽量构建数组桶实现这种hash关系
for (int i = 2; i <= n / i; i ++ ) if (n % i == 0) { primes[ ++ cnt] = i; while (n % i == 0) { n /= i; num[cnt] ++ ; } } if (n > 1) primes[ ++ cnt] = n, num[cnt] = 1;
这个质因数分解相信大家都能够理解,y总模板套就完事了。
接下来质因数分解好了之后 我们进行二分答案
首先,左区间我们设为1,右区间设为1e9(因为你的值最大就是这么多,其实也不必这么大)。
我们从这个区间里找出一个mid,再对mid进行判断是否为满足条件的n,
如果满足,那么我们就往左边继续找,同时记下此时的mid。
至于为什么往左边?因为我们是找最小的n,如果此时的mid是满足的,但我们不知道它是否为最小的,所以我们要将查找的范围往左边移,即将r往左移。否则l 右移。
int l = 1, r = 1e9; while (l < r) { int mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; }
接下来就是check函数了 这里用到了一个我新学到的知识 ,求n!质因数因子的个数
可以手写模拟一下,方法来自这里
假如求10!中质因子2的个数,就是先对 t1=10/2=5,t2=t1/2=5/2=2, t3=t2/2=2/2=1,t4=0。所以总个数等于t1+t2+t3=8个
所以我们对应本题目中,求p的各个质因子primes[i]的个数num[i],是否全部满足各个质因子个数num[i]小于等于二分答案的这个值x!的各个质因子个数
具体应用题目中就是
bool check(int x) { for (int i = 1; i <= cnt; i ++ ) { int t = x, sum = 0; while (t) { sum += t / primes[i]; t /= primes[i]; } if (sum < num[i]) return false; } return true; }
综上 全部代码呈现
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> #include <vector> #include <map> using namespace std; typedef long long LL; const int N = 10010; int primes[N], num[N], cnt; bool check(int x) { for (int i = 1; i <= cnt; i ++ ) { int t = x, sum = 0; while (t) { sum += t / primes[i]; t /= primes[i]; } if (sum < num[i]) return false; } return true; } int main() { int t; cin >> t; while (t -- ) { memset(num, 0, sizeof num); memset(primes, 0, sizeof primes); LL n; cin >> n; cnt = 0; for (int i = 2; i <= n / i; i ++ ) if (n % i == 0) { primes[ ++ cnt] = i; while (n % i == 0) { n /= i; num[cnt] ++ ; } } if (n > 1) primes[ ++ cnt] = n, num[cnt] = 1; int l = 1, r = 1e9; while (l < r) { int mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } cout << l << endl; } return 0; }