Sanae's blog

By Sanae, history, 4 months ago, In English

Tutorial for CF1167G

English Version

Hints

What stops the rotation?

A brute-force solution is straightforward, but how can we optimize it?

Step 1

There are two cases in which the rotation stops:

  1. the ray touches the building
  2. the building touches another building.

In the second case, write the left building is $$$x$$$ sway from the bending point and the right one is $$$y$$$ away from the bending point.

With some geometry knowledge, the angle is

$ \alpha=\begin{cases} \tan^{-1}(\frac{1}{x}) & x=y\ \tan^{-1}(\frac{1}{\max(x,y)}) & |x-y|=1\ \textrm{useless} & \textrm{otherwise} \end{cases} $

In the third case , they won't reach each other.

So we can easily write a brute force $$$O(nm)$$$.

code

Step 2

The crucial idea is that if $$$|x| \gt 7000$$$, we don't need to calculate it.

It's because, due to the "not sparse" condition that two buildings have already touched each other , or a building has already touched the ray.

Now it comes down to $$$O(md)$$$.

Step 3

If we can represent the state before and after rotation using arrays, we only need to find positions where both values are equal to $$$1$$$.It's easy to speed up it with bitset.

Note: some buildings may be included in the bitset but are not actually activated. A set is used to check whether a building is valid.

$$$O(\frac{md}{w})$$$

code

Step 4

Handwrite bitset !

code

Reference

https://mirror.codeforces.com/blog/entry/67058

https://www.cnblogs.com/yijan/p/bitset.html

中文版

Hint

是什么阻止了旋转?

暴力解法是显然的,但该如何优化?

Step 1

旋转停止有两种情况:

  1. 射线碰到某一栋建筑;
  2. 一栋建筑碰到了另一栋建筑。

在第二种情况下,设左边的建筑距离转折点为 $x$,右边的建筑距离转折点为 $y$。

利用一些几何知识,可以得到停止时的角度:

$ \alpha= \begin{cases} \tan^{-1}\left(\frac{1}{x}\right) & x = y \ \tan^{-1}\left(\frac{1}{\max(x,y)}\right) & |x — y| = 1 \ \text{无意义} & \text{其他情况} \end{cases} $

在第三种情况下,两栋建筑不会相互接触。

因此,我们可以很容易地写出一个时间复杂度为 $$$O(nm)$$$ 的暴力算法。

代码

Step 2

关键的观察是:当 $$$|x| \gt 7000$$$ 时,我们不需要再进行计算。

这是因为在“不稀疏”的条件下,更近的两栋建筑已经发生接触,或者某一栋建筑已经先接触到了射线。

因此,时间复杂度可以降低到 $O(md)$。

Step 3

如果我们能用数组表示旋转前后的状态,那么只需要找到前后状态都为 (1) 的位置即可。

使用 bitset 可以很容易地对这一过程进行加速。

注意:有些建筑可能被计入 bitset 中,但实际上并未被激活,因此需要使用一个集合来判断其有效性。

时间复杂度为:

$ O\left(\frac{md}{w}\right) $

代码

Step 4

手写 bitset

代码

参考资料

https://mirror.codeforces.com/blog/entry/67058

https://www.cnblogs.com/yijan/p/bitset.html

  • Vote: I like it
  • +14
  • Vote: I do not like it