UVa 12571
題目
http://domen111.github.io/UVa-Easy-Viewer/?12571
給定 $N$ 個數字 $x_1, x_2, \dots, x_N$,以及 $Q$ 筆詢問
每筆詢問會有一個數字 $a$,求 $a \texttt{ & } x_i$ 的最大值為多少
$$1 \leq N \leq 100000 \
1 \leq Q \leq 30000 \
0 \leq x_i \leq 10^9 \
0 \leq a < 230
$$
想法1
雖然說暴力地把每個數字都做 & 一次取最大值會太慢(沒錯,我在這題 TLE 了好幾次)
但是注意到 $a$ 的範圍都在 $230$ 以內,也就是說超過 $2^7$ 這個 bit 的部分都可以直接忽略掉
所以我們就只需要注意所有 $255 = 11111111_2$ 以內的部分即可
找出一開始 $N$ 個數字中所有在 $0$~$255$ 以內的部分記錄起來
接下來如果要詢問,我們只需要針對這 $256$ 個數字檢查是否有出現過,然後找出 & 後的最大值即可
如此一來我們就不需要掃過長度 $N$ 的序列,而只需要掃過長度 $256$ 的序列
Code
1 | //By Koios1143 |
時間複雜度分析
每筆測資輸入時間複雜度為 $O(N + Q)$
每筆測資找出 used
的時間複雜度為 $O(N)$
令 $M = 256$,每筆詢問時間複雜度為 $O(R)$
總時間複雜度為 $O(t(N + Q + QR))$
想法2
如果我們直接把整個序列掃過去時間太慢,可能的因素是重複檢查相同的數字
也就是說,有些數字有出現的 bit 可能被其他數字完全覆蓋,那麼我們就只需要找那些盡量多 bit 的做一次 & 運算,其效果等同跟這群數字都做一次 &
舉範例的例子來說,輸入的 $N$ 個數字為 $1, 2, 3$,轉換成二進位後
$$
1 = 01_2 \
2 = 10_2 \
3 = 11_2
$$
很顯然的,與其跟三個數字都做一次 &,倒不如只跟 $3$ 做一次 &,因為 $3$ 包含了 $1, 2$ 的所有 bit
那麼我們只要想辦法留下這種會覆蓋掉別人的數字即可
那麼要怎麼篩選呢?
我們可以枚舉每個尚未被篩除的數字跟其他數字做 |
運算,如果 $a | b = a$,那就表示 $b$ 的所有 bit 都被包含在 $a$ 裡面
這裡有個優化的想法
那些會被篩掉的數字必定都是被比她還大的數字篩掉的,畢竟大的數字在更高位會出現 $1$
那麼,一開始就把數字排序好,必定可以保證由大到小篩選不會漏篩,而且每次都可以從最後一個篩除的數字往下繼續篩
如此一來就不需要每次都跟全部數字篩看看了
最後只需要把篩出來的數字跟詢問做 & 找最大值即可
Code
1 | //By Koios1143 |
複雜度我不太知道要怎麼估,但是至少在 UVa 上是比第一個想法快了 0.02 秒