Description
Link:CF2153E
设 v p ( x ! ) v_p(x!) v p ( x !) 表示 x ! x! x ! 可以分解出多少个 p p p 的乘积。
勒让德定理:
v p ( x ! ) = ∑ j = 1 ⌊ log k x ⌋ ⌊ x p j ⌋ v_p(x!) = \sum_{j = 1}^{\lfloor \log_k x \rfloor} \left\lfloor \frac{x}{p^j} \right\rfloor
v p ( x !) = j = 1 ∑ ⌊ l o g k x ⌋ ⌊ p j x ⌋
当 p p p 为合数时,记 p = ∑ i = 1 m p i c i p = \sum_{i = 1}^m p_i^{c_i} p = ∑ i = 1 m p i c i
v p ( x ! ) = min i = 1 m ⌊ v p i ( x ! ) c i ⌋ v_p(x!) = \min_{i = 1}^m \left\lfloor \frac{v_{p_i}(x!)}{c_i} \right\rfloor
v p ( x !) = i = 1 min m ⌊ c i v p i ( x !) ⌋
设
w k ( a , b ) = { min ( v k ( a ! ) , v k ( b ! ) ) if v k ( a ! ) ≠ v k ( b ! ) ; 10 100 otherwise. w_k(a, b) = \begin{cases}
\min(v_k(a!), v_k(b!)) & \text{if }v_k(a!) \neq v_k(b!) \text{;}\\
10^{100} & \text{otherwise.}
\end{cases}
w k ( a , b ) = { min ( v k ( a !) , v k ( b !)) 1 0 100 if v k ( a !) = v k ( b !) ; otherwise.
设
f m ( a , b ) = min 2 ≤ k ≤ m w k ( a , b ) f_m(a, b) = \min_{2 \leq k \leq m} w_k(a, b)
f m ( a , b ) = 2 ≤ k ≤ m min w k ( a , b )
给出两个整数 n , m n, m n , m ,你需要计算 ∑ 1 ≤ x < n f m ( x , n ) \sum\limits_{1 \leq x < n}f_m(x, n) 1 ≤ x < n ∑ f m ( x , n ) 。
数据范围:2 ≤ n ≤ m ≤ 10 7 2 \leq n \leq m \leq 10^7 2 ≤ n ≤ m ≤ 1 0 7 。可以证明给定条件下答案严格小于 10 100 10^{100} 1 0 100 。
时空限制:3 3 3 s / 512 512 512 MiB。
Solution
设 p 0 p_0 p 0 是小于等于 n n n 中最大的质数,对于 x < p 0 x < p_0 x < p 0 显然有 f m ( x , n ) = 0 f_m(x, n) = 0 f m ( x , n ) = 0 (因为取 k = p 0 k = p_0 k = p 0 即有 w k ( x , n ) = 0 w_k(x, n) = 0 w k ( x , n ) = 0 )。
打表发现 10 7 10^7 1 0 7 以内,相邻素数的差值最大为 154 154 154 。于是我们真正要考虑的 p 0 ≤ x < n p_0 \leq x < n p 0 ≤ x < n 部分,实际上并不大。
性质 :对于 a ≤ b a \leq b a ≤ b ,有 v k ( a ! ) ≤ v k ( b ! ) v_k(a!) \leq v_k(b!) v k ( a !) ≤ v k ( b !) 。
由于 a ! ∣ b ! a! \mid b! a ! ∣ b ! ,易证。
性质 :w k ( a , b ) ≥ min i = 1 m w p i c i ( a , b ) w_k(a, b) \geq \min_{i = 1}^m w_{p_i^{c_i}}(a, b) w k ( a , b ) ≥ min i = 1 m w p i c i ( a , b ) 。
对于 1 ≤ i ≤ m 1 \leq i \leq m 1 ≤ i ≤ m ,设 a i = ⌊ v p i ( a ! ) c i ⌋ a_i = \left\lfloor \frac{v_{p_i}(a!)}{c_i} \right\rfloor a i = ⌊ c i v p i ( a !) ⌋ ,b i = ⌊ v p i ( b ! ) c i ⌋ b_i = \left\lfloor \frac{v_{p_i}(b!)}{c_i} \right\rfloor b i = ⌊ c i v p i ( b !) ⌋ 。
若 v k ( a ! ) = v k ( b ! ) v_k(a!) = v_k(b!) v k ( a !) = v k ( b !) ,则 w k ( a , b ) = 10 100 w_k(a, b) = 10^{100} w k ( a , b ) = 1 0 100 ,不等式成立。
若 v k ( a ! ) ≠ v k ( b ! ) v_k(a!) \neq v_k(b!) v k ( a !) = v k ( b !) ,即 min { a i } < min { b i } \min\{a_i\} < \min\{b_i\} min { a i } < min { b i } ,设 a x = min { a i } a_x = \min\{ a_i \} a x = min { a i } ,则 a x < b x a_x < b_x a x < b x ,此时有 w k ( a , b ) = a x = w p x c x ( a , b ) w_k(a, b) = a_x = w_{p_x^{c_x}}(a, b) w k ( a , b ) = a x = w p x c x ( a , b ) 。
该性质告诉我们,我们只需枚举形如 k = p c k = p^c k = p c 的数计算 f m ( x , n ) f_m(x, n) f m ( x , n ) 即可。
性质 :只需枚举形如 k = p c k = p^c k = p c 且 p p p 被 [ p 0 , n ] [p_0, n] [ p 0 , n ] 中至少一个数整除的数。
记 n ! = p 0 ! ( p 0 + 1 ) ⋯ n n! = p_0!(p_0 + 1) \cdots n n ! = p 0 ! ( p 0 + 1 ) ⋯ n ,若 p p p 不被 [ p 0 , n ] [p_0, n] [ p 0 , n ] 中的某个数整除,则必有 v k ( p 0 ! ) = v k ( n ! ) v_k(p_0!) = v_k(n!) v k ( p 0 !) = v k ( n !) 。
性质 :答案必定严格小于 10 100 10^{100} 1 0 100 。
考虑将 x − 1 x - 1 x − 1 变成 x x x ,对于 x x x 的某个质因数 p p p ,必有 v p ( ( x − 1 ) ! ) < v p ( x ! ) v_p((x - 1)!) < v_{p}(x!) v p (( x − 1 )!) < v p ( x !) ,因为 ⌊ x p ⌋ \left\lfloor \frac{x}{p} \right\rfloor ⌊ p x ⌋ 发生了变化。
于是将 [ p 0 , n ] [p_0, n] [ p 0 , n ] 中所有数的质因数拿出来,枚举形如 k = p c k = p^c k = p c 的数计算 f m ( x , n ) f_m(x, n) f m ( x , n ) 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 #include <bits/stdc++.h> #define debug(a) std::cout << #a << "=" << (a) << ' ' using s64 = long long ;using u64 = unsigned long long ;template <class T >inline void chmin (T &x, const T &y) { if (x > y) { x = y; } } template <class T >inline void chmax (T &x, const T &y) { if (x < y) { x = y; } } const int V = 1e7 , MaxV = V + 10 ;int primeCount, prime[MaxV], fac[MaxV];int low[MaxV];void sieve (const int &n) { for (int i = 2 ; i <= n; i ++) { if (!fac[i]) { prime[++ primeCount] = i, fac[i] = i; low[i] = i; } for (int j = 1 ; j <= primeCount; j ++) { if (prime[j] > fac[i] || prime[j] > n / i) break ; fac[i * prime[j]] = prime[j]; low[i * prime[j]] = prime[j] * (i % prime[j] == 0 ? low[i] : 1 ); } } } int n, m;int factorialIndex (int n, int p) { int cnt = 0 ; for (int v = p;; v *= p) { cnt += n / v; if (v > n / p) { break ; } } return cnt; } void work () { std::cin >> n >> m; int p0 = n; while (fac[p0] != p0) { p0 --; } std::vector<int > key; for (int i = p0; i <= n; i ++) { int x = i; while (x > 1 ) { key.push_back (fac[x]); x /= low[x]; } } std::sort (key.begin (), key.end ()); key.erase (std::unique (key.begin (), key.end ()), key.end ()); s64 ans = 0 ; for (int i = p0; i < n; i ++) { int cur = 0x3f3f3f3f ; for (int p : key) { int cnti = factorialIndex (i, p), cntn = factorialIndex (n, p); for (int v = p, c = 1 ;; v *= p, c ++) { int vi = cnti / c, vn = cntn / c; if (vi < vn) { chmin (cur, vi); } if (v > m / p) { break ; } } } ans += cur; } std::cout << ans << '\n' ; } int main () { std::ios::sync_with_stdio (0 ); std::cin.tie (0 ); sieve (V); int T; std::cin >> T; while (T --) { work (); } return 0 ; }