洛谷 P3579 [POI2014]PAN-Solar Panels 蓝 题解
P3579 题解
前言
感觉大部分题解讲的不是很清楚,在 \(haosen\) 的讲解中,我才会了这道题……
思路
看到数据范围,线性必然超时,那么复杂度一般就为 \(O(\log n)\) 或者 \(O(\sqrt{n})\),又看到这是一个数学题,心里应该有暗示,可能会用到整数分块。
不过第一件事总是:挖掘性质!
你会发现,对于任意一个数 \(x\),如果 \(a \sim b\) 中存在一个数是 \(x\) 的倍数,且 \(c \sim d\) 中存在一个数是 \(x\) 的倍数,那么 \(x\) 就为一个合法的答案,但可能不是最优的。这个比较简单,就不赘述了。
那就直接枚举答案 \(x\),从 \(1\) 到 \(\min(b,d)\) 枚举,逐个判断 \(x\) 合不合法,取最大值。
显然这样做是超时的。
其实如果 \(x\) 是合法的,只需要满足:
为什么?我们就拿第一个不等式举例子:\(\left\lfloor \dfrac{b}{x} \right\rfloor\) 表示 \(1 \sim b\) 中有几个数是 \(x\) 的倍数,同理,\(\left\lfloor \dfrac{a-1}{x} \right\rfloor\) 表示 \(1 \sim a-1\) 中有几个数是 \(x\) 的倍数。两式相减,就得到了 \(a \sim b\) 中有几个数是 \(x\) 的倍数,只要有一个数是 \(x\) 的倍数,就满足答案。第二个不等式同理。
我们还是拿第一个不等式为例,进行化简:
\(\left\lfloor \dfrac{b}{x} \right\rfloor - \left\lfloor \dfrac{a-1}{x} \right\rfloor \ge 1 \Rightarrow \left\lfloor \dfrac{b}{x} \right\rfloor \ge 1 + \left\lfloor \dfrac{a-1}{x} \right\rfloor \Rightarrow \left\lfloor \dfrac{b}{x} \right\rfloor > \left\lfloor \dfrac{a-1}{x} \right\rfloor\)
接下来,我认为是最难的一步,考虑 \(\left\lfloor \dfrac{b}{x} \right\rfloor > \left\lfloor \dfrac{a-1}{x} \right\rfloor\) 还能怎么化简。
如果我们把除以 \(x\) 得到的商相等的所有数都合并成一个块儿,并把每个块儿按顺序编号,那么这个式子就表示 \(b\) 所在的块的编号要严格大于 \(a-1\) 所在的块。
式子就可以变成这样:\(x\left\lfloor \dfrac{b}{x} \right\rfloor > a-1\)
为啥要变成这样?方便整数分块!现在只需要对 \(\left\lfloor \dfrac{b}{x} \right\rfloor\) 整数分块就行哩~
最后的最后,要满足的条件其实就变成了:
Code
#include <iostream>
using namespace std;
int T;
int a, b, c, d, ans;
int main()
{
cin >> T;
while (T -- )
{
cin >> a >> b >> c >> d;
for (int L = 1, R = 1; L <= min(b, d); L = R + 1)
{
R = min(b / (b / L), d / (d / L));
if (R * (b / R) > a - 1 && R * (d / R) > c - 1) ans = R;
}
cout << ans << endl;
}
return 0;
}
总结
先明确大方向,再进行分析,最后优化。
完结撒花!