Lemma
Legendre 定理
在正数\(n!\)的质因数分解中, 质数\(p\) 的指数记作\(v_p(n!)\),则有等式\(v_p(n!)=\sum\limits_{j=1}^{\infty} \lfloor\frac{n}{p^k} \rfloor\)
LL f(LL n, LL p) {
if (n == 0) return 0;
n /= p;
return n + f(n, p);
}
思路
对于给定的K求其最小数N满足\(K \mid N!\) , 首先对于满足该条件的\(N\), 有以下推论
-
任意的\(K \mid X!\) , 其中 \(X>=N\)
-
将\(K\)素因数分解 , 那么其每个素因数的幂数均小于X素因数分解中该数的幂数
由此,我们可以得到进一步结论:
- 当\(1 \leq X < N\)时, 那么K的素因数在X中要么不存在,要么在X中其素因数的幂数小于K中的幂数, 可以总结为在X中的素因数小于K中的素因数幂次(不存在时,幂次为0)。 当\(N \leq X\) 时,其素因数幂次均满足大于等于K中的幂次。
由此,我们可以得到二分的做法
时间复杂度\(O(\sqrt k)\)
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <functional>
#include <utility>
#include <unordered_set>
#include <unordered_map>
#define INF 0x3f3f3f3f
#define IOS ios::sync_with_stdio(false);
#define rep(i, j, k) for(int i = j; i <= k; ++ i)
#define per(i, j, k) for(int i = j; i >= k; -- i)
#define dbg1(a) cout << a << endl;
#define dbg2(a, b) cout << a << " " << b << endl;
#define dbg3(a, b, c) cout << a << " " << b << " " << c << endl;
#define pb(x) push_back(x)
#define eb(x) emplace_back(x)
#define all(x) x.begin(), x.end()
#define f first
#define s second
#define lc p<<1
#define rc p<<1|1
using namespace std;
typedef long long LL;
typedef priority_queue<int, vector<int>, greater<int>> S_HEAP;
typedef priority_queue<int> B_HEAP;
typedef pair<string, int> PSI;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
LL f(LL n, LL p) {
if (n == 0) return 0;
n /= p;
return n + f(n, p);
}
int main() {
LL k;
cin >> k;
vector<PLL> v1;
LL x = k;
for (LL i = 2; i * i <= x; i ++) {
if (x % i) continue;
int cnt = 0;
while (x % i == 0) {
x /= i;
cnt ++;
}
v1.push_back({i, cnt});
}
if (x != 1) v1.push_back({x, 1});
LL r1 = k, l1 = 0;
while (l1 < r1) {
LL mid = l1 + r1 >> 1;
bool ok = true;
for (auto x: v1) {
if (f(mid, x.f) < x.s) ok = false;
}
if (ok) r1 = mid;
else l1 = mid + 1;
}
cout << l1 << endl;
}