E2. Divisible Numbers (hard version)
E2. Divisible Numbers (hard version)
This is an hard version of the problem. The only difference between an easy and a hard version is the constraints on $a, b, c$ and $d$.
You are given $4$ positive integers $a, b, c, d$ with $a<c$ and $b<d$. Find any pair of numbers $x$ and $y$ that satisfies the following conditions:
- $a < x \leq c$ , $b < y \leq d$,
- $x \cdot y$ is divisible by $a \cdot b$.
Note that required $x$ and $y$ may not exist.
Input
The first line of the input contains a single integer $t$ $(1 \leq t \leq 10)$, the number of test cases.
The descriptions of the test cases follow.
The only line of each test case contains four integers $a, b, c$ and $d$ $(1 \leq a< c \leq {10}^{9}, 1 \leq b < d \leq {10}^{9})$.
Output
For each test case print a pair of numbers $a < x \leq c$ and $b < y \leq d$ such that $x \cdot y$ is divisible by $a \cdot b$. If there are multiple answers, print any of them. If there is no such pair of numbers, then print $\text{-1 -1}$.
Example
input
10 1 1 2 2 3 4 5 7 8 9 15 18 12 21 14 24 36 60 48 66 1024 729 373248 730 1024 729 373247 730 5040 40320 40319 1000000000 999999999 999999999 1000000000 1000000000 268435456 268435456 1000000000 1000000000
output
2 2 4 6 12 12 -1 -1 -1 -1 373248 730 -1 -1 15120 53760 -1 -1 536870912 536870912
解题思路
参考easy version。
如果像easy version一样枚举$x$那么必然会超时。在easy version中,我们枚举$x$是为了得到$\gcd(x, a \cdot b)$,也就是$a \cdot b$的一个因子,而$\frac{a \cdot b}{\gcd(a \cdot b, x)}$就是$a \cdot b$的另外一个因子,然后根据这个因子的倍数去找到$y$($x$也是因子$\gcd(x, a \cdot b)$的倍数)。
那么我们就可以想到能否枚举$a \cdot b$的所有因子,对于其中一对因子$a'$和$b'$($a' \cdot b' = a \cdot b$),假设$a' \mid x$,$b' \mid y$,如果在区间$[a+1, c]$存在$a'$的倍数,在区间$[b+1, d]$存在$b'$的倍数,那么就存在一组解。判断是否在区间存在某个数的倍数的方法和easy version中的一样,就是看一下大于左端点的最小的倍数是否不超过右端点。
这里要枚举出所有$a \cdot b$的因子,感觉上好像会超时,实际上在不超过${10}^{9}$的数中,包含因子最多的那个数的因子个数为$1344$,意味着在${10}^{18}$范围内的数中,因子个数最多不超过${1344}^2$。
因此我们可以先枚举出$a \cdot b$的因子中,所有不超过$c$的因子$t$,同时$t$还要满足$\frac{a \cdot b}{t} \leq d$。然后再遍历刚才得到的所有因子$d$,如果在区间$[a+1, c]$存在$d$的倍数,且在区间$[b+1, d]$存在$\frac{a \cdot b}{d}$的倍数,那么就存在一组解。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 LL a, b, c, d; 7 LL m; 8 unordered_map<int, int> mp; 9 vector<pair<int, int>> p; 10 vector<int> ds; 11 12 void divide(int x) { 13 for (int i = 2; i <= x / i; i++) { 14 while (x % i == 0) { 15 mp[i]++; 16 x /= i; 17 } 18 } 19 if (x > 1) mp[x]++; 20 } 21 22 void dfs(int u, LL prod) { 23 if (prod > c) return; // 因子超过[a+1, c]这个范围 24 if (u == p.size()) { 25 if (m / prod <= d) ds.push_back(prod); // 另外一个因子超过[b+1, d]这个范围 26 return; 27 } 28 LL t = 1; 29 for (int i = 0; i <= p[u].second; i++) { 30 dfs(u + 1, prod * t); 31 t *= p[u].first; 32 } 33 } 34 35 void solve() { 36 mp.clear(), p.clear(), ds.clear(); 37 cin >> a >> b >> c >> d; 38 m = a * b; 39 divide(a), divide(b); // 质因数分解 40 for (auto &it : mp) { 41 p.push_back(it); 42 } 43 dfs(0, 1); // 求a*b的因子 44 for (int i = 0; i < ds.size(); i++) { 45 int x = ds[i], y = m / x; 46 x = (a / x + 1) * x, y = (b / y + 1) * y; 47 if (x <= c && y <= d) { // 在区间范围内存在因子倍数 48 printf("%d %d\n", x, y); 49 return; 50 } 51 } 52 printf("-1 -1\n"); 53 } 54 55 int main() { 56 int t; 57 scanf("%d", &t); 58 while (t--) { 59 solve(); 60 } 61 62 return 0; 63 }
参考资料
Codeforces Round #828 (Div. 3) Editorial:https://codeforces.com/blog/entry/108101
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16807598.html