1. 程式人生 > 其它 >[CF878D] Magic Breeding 題解

[CF878D] Magic Breeding 題解

你谷 link

CF link

又是一道 bitset 科技題,但是思維難度也還是很高的。

考慮先弱化一下題目,如果特徵只有 \(0/1\) 該怎麼做,考慮對於 \(0/1\) 來說,\(\min/\max\) 可以看成 \(\operatorname{bitand}/\operatorname{bitor}\) 操作,那麼我們考慮如果將所有生物的一種特徵單獨做會怎麼樣,現在的問題就變成了給定一個數組,每次新生成一個元素表示為之前選取兩個值的 \(\operatorname{bitand}/\operatorname{bitor}\),現在的情況是因為有 \(10^5\) 種特徵,每一位單獨做時間複雜度無法接受,但是發現因為初始陣列只有 \(12\)

個生物,所以如果特徵只有 \(0/1\) 的話最多隻有 \(2^12=4096\) 種情況,時間複雜度並不是不能接受,而且可以用 bitset&| 操作加速,性質非常優秀。

考慮如何將 \(10^9\) 的值域轉化成 \(0/1\),這可以說是一個經典套路,首先我們發現因為初始只有 \(12\) 個值,而 \(\min/\max\) 操作不會產生新的值,所以值最多隻有 \(12\) 種,對於將大值域轉化成 \(0/1\) 一個經典的手段在二分時經常用到,就是設一個閾值 \(\text{limit}\),如果一個值比 \(\text{limit}\) 小就是 \(0\),否則就是 \(1\),這裡我們也可以照用,我們一共有 \(12\)

種閾值,難道每個都維護一遍嗎?實際上不用這麼麻煩。考慮前面我們發現一共就 \(4096\) 種情況,我們可以直接設任意一個值為 \(0/1\) 的情況,全部記錄下來,即設 \(f_{i,sta}\) 表示 \(sta\) 對應的所有位置的值都為 \(1\) 的情況下第 \(i\) 個值是什麼,然後發現因為 \(\min/\max\) 操作對應 \(\operatorname{bitand}/\operatorname{bitor}\),且在生成 \(i\) 時轉移每個 \(sta\) 操作的方法是一樣的,所以可以用 bitset 優化,然後查詢操作直接從大到小列舉閾值更新 \(sta\) 直到答案為 \(f_{i,sta}=1\)
,初始化就是 \(f_{i,sta}=i\subseteq sta\)

程式碼並沒有想象中那麼難。