题目大意
给出两段区间 [ l 1 , r 1 ] , [ l 2 , r 2 ] [l_1, r_1] ,[l_2, r_2] [l1,r1],[l2,r2],设 d 1 = ∏ i = l 1 r 1 , d 2 = ∏ i = l 2 r 2 d_1 = \prod_{i = l_1}^{r_1}, d_2 = \prod_{i = l_2}^{r_2} d1=∏i=l1r1,d2=∏i=l2r2,问是否 d 1 ∣ d 2 d_1 | d_2 d1∣d2,即前者整除后者。
解题思路
这题拿到思路后一直想着对每个数质因数分解的方法去求,但是无奈要么 T L E TLE TLE要么 M L E MLE MLE,实际上单纯的质因数分解已经差不多接近超时了,如果再加上 u n o r d e r e d _ m a p unordered\_map unordered_map的常数肯定就挂了。
质因数层面很好想,就是对于第一个乘积的每个质因数的幂次,必定小于等于第二个乘积中的幂次。乘积无法维护,对每个数质因数分解常数很大,于是我们可以转化一下,根据前缀和的思想也就是 d 1 = r 1 ! ( l 1 − 1 ) ! , d 2 = r 2 ! ( l 2 − 1 ) ! d_1 = \frac{r_1!}{(l_1 - 1)!}, d_2 = \frac{r_2!}{(l_2 - 1)!} d1=(l1−1)!r1!,d2=(l2−1)!r2!,然后只需要枚举所有的质数,求阶乘质因数的时间复杂度为 O ( l o g n ) O(logn) O(logn),设 1 e 7 1e7 1e7内质数的个数为 m m m,那么本题的时间复杂度就是 O ( m l o g n ) O(mlogn) O(mlogn)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ENDL "\n"
const int maxn = 1e7 + 10;
vector<int> prime;
bitset<maxn> vis;
void euler() {
for (int i = 2; i < maxn; i++) {
if (!vis[i]) prime.push_back(i);
for (int j = 0; j < prime.size() && 1LL * i * prime[j] < maxn; j++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
}
ll cal(int n, int p) {
ll ans = 0;
while (n) {
ans += n / p;
n /= p;
}
return ans;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T, l, r, L, R;
euler();
cin >> T;
while (T--) {
cin >> l >> r >> L >> R;
bool ok = 1;
for (auto p : prime) {
ll x = cal(r, p) - cal(l - 1, p), y = cal(R, p) - cal(L - 1, p);
if (x > y) {
ok = 0;
break;
}
}
if (ok)
cout << "Yes" << ENDL;
else
cout << "No" << ENDL;
}
return 0;
}