Codeforces - 1744E2 - Divisible Numbers (hard version)(数论 + 暴力 + 思维 、 *1900)
1744E2 - Divisible Numbers (hard version)(⇔源地址)
tag
⇔数论、⇔暴力、⇔思维、⇔*1900。
题意
给出四个数 \(a,b,c,d\) ,请你找到任意一对 \(\{X,Y\}\) ,使得满足:
- \(a<X\le c,b<Y\le d\) ;
- \(X*Y\) 是 \(a*b\) 的倍数。
思路
正解
由题目条件,能够得到 \(X*Y=K*a*b(1 < K)\),我们将 \(a、b\) 拆分为 \(a=x_1*y_1,b=x_2*y_2\) ,那么式子就变成 \(X*Y=K*x_1*x_2*y_1*y_2\) 。我们可以分解出 \(a、b\) 的全部因数,然后暴力枚举,代入式子中求解。
下面讨论如何代入式子中得到答案。假设我们枚举出来的因数是 \(y1、y2\) ,那么通过 \(a*b=x_1*x_2*y_1*y_2\) 可以得到 \(x_1*x_2=\dfrac{a*b}{y_1*y_2}\) 。这个时候,我们的 \(K\) 并没有参与计算,我们再拆分 \(K=k_1*k_2\) ,使得\(\left\{\begin{matrix} Y=k_1*y_1*y_2 \\ X=k_2*x_1*x_2 \end{matrix}\right.\) ,那么如何找到最小的符合条件的 \(X、Y\) 呢?
以求解 \(Y\) 为例,我们整理一下已经有的东西:已知有 \(\left\{\begin{matrix} b < Y \le d \\ Y是 y1*y2的倍数 \\ b、d、y1、y2已知 \end{matrix}\right.\) ,那么大于 \(b\) 的最小的 \(Y\) 即为 \(\left \lfloor \dfrac{b}{y_1*y_2} + 1 \right \rfloor * y_1*y_2\) ,只需要将其与 \(d\) 再做一次比较即可。\(X\) 同理。
分析正确性:使用试除法分解因数,\(\mathcal O(\sqrt N)\) ;而 \(10^9\) 以内的数字的因数最多的数量为 \(1344\) ,所以使用暴力枚举,\(\mathcal O(1344^2)\) ;最后一步暴力求解的复杂度为 \(\mathcal O(1)\) ,能够通过。
附:因数数量表
\(\pmb {n \le}\) \(\pmb {10^1}\) \(\pmb {10^2}\) \(\pmb {10^3}\) \(\pmb {10^4}\) \(\pmb {10^5}\) \(\pmb {10^6}\) \(\pmb {10^7}\) \(\pmb {10^8}\) \(\pmb {10^9}\) \(\pmb {最大因数数量}\) 4 12 32 64 128 240 448 768 1344
后日谈
在查阅资料时,发现有很多人都是使用 \(\tt dfs\) 来替代\(a*b=x_1*x_2*y_1*y_2\) 这一步的,其本质思路是一致的,而 \(\tt dfs\) 码量较多,故这里不再单独写一份代码。这题对于数学的思维要求极高,就我而言,用式子直接计算“大于 \(b\) 的最小的 \(Y\) ”这一步可能比较难以想到,但是看过式子之后也就感觉不过如此,还是经验的问题,总的来说只要想到了正确方法,这道题就是纯打卡题了。
AC代码
点击查看代码
set<int> clac(int x) {
set<int> num;
for (int i = 1; i <= x / i; ++ i) {
if (x % i == 0) num.insert(i), num.insert(x / i);
}
return num;
}
void Solve() {
int a, b, c, d; cin >> a >> b >> c >> d;
set<int> num1 = clac(a), num2 = clac(b);
for (auto i : num1) {
for (auto j : num2) {
int x = i * j;
int y = a * b / x;
x = (a / x + 1) * x;
y = (b / y + 1) * y;
if (a < x && x <= c && b < y && y <= d) {
cout << x << " " << y << endl;
return;
}
}
}
cout << -1 << " " << -1 << endl;
}
错误次数:2
文 / WIDA
2022.10.24 成文
首发于WIDA个人博客,仅供学习讨论