就是給出乙個數 \(k\),再給出乙個邊長為 \(n=2^\) 的矩陣每個元素是 \(w_\),然後要求我們求出乙個 \([0,n-1]\) 序列 \(p\) 使 他的\(\sum_^ w_,p_i}\) 最小,同時這個序列要滿足對於 乙個小於等於 \(k\) 的 \(j\) 滿足分成 \(2^\) 塊,並且這些塊內的 \(p_i\)的第 \(j\) 位都相同。
前兩天模擬賽做到一道特別厲害的題,來的分享想一下
其實這題是司機出的t3,照理說應該是沒人切得動的,但是「大海」不但切了,還把司機的標算吊打了一發。
標算複雜度: \(o(n^3)\)
大海複雜度: \(o(n^2k)\)
\(k\) 的範圍和 \(log\) 同階。
那麼我們還研究司機的演算法搞個雞毛,看「大海」啊。
我們先拿樣例來找找規律:
1 0 3 2
我們把他二進位制分解:
01 00 11 10
我們發現分個組:
01 00 | 11 10
他們的第一位的數是不同的(左邊是0,右邊是1)。
這個根據題目要求其實可以簡單發現。
因為前一段是第一位是0,如果後一段和前一段的第一位相同的話就會重複,同時之後還要保證他們的第2位相同那麼就會重複,那就非常尷尬了(我連我自己)。
所以要從最小的長度 \(2\) 開始,保證這種尷尬情況不出現。
所以我們發現乙個確定下乙個數填什麼的乙個方法,但是具體怎麼確定把那一位取個反讓他們不同捏?
我們對他的編號觀察一下:
0 1 2 3
我們這樣看不出什麼鬼東西,我們對他二進位制分解一下:
00 01 10 11
歐,好像有點東西?我們發現好像在編號為 \(2\) 的時候發生了取反,並且取反位置好像和這個東西的後面有幾個 \(0\) 有關係,不錯,好像有點進展。\(0\) 根 \(lowbit\) 有點關係。
但是我們還是不知道確定下一位那個位取反之後怎麼知道後一位到底會是多少。
我們動了動腦yy了一下,好像又有點眉目了?
好像不能直接求出下乙個,因為要取 \(min\) 所以這就很顯然了,我們得列舉。
但是直接列舉的話好像對我們剛才得出的資訊沒什麼用,我們可以利用一下題目,如果我們已經確定了前一位是啥,那不是我們對想應位置取反之後就可以推出這一位序列裡選什麼。
但是還是要列舉那些前面相同那些從 \(lowbit\) 開始不一樣的那些編號。
那麼我們基本確定了乙個方案:
設 \(f[k][num]\) 表示前 \(k\) 個,上乙個填了 \(num\) 的最小序列值。
那麼我們大力列舉下乙個數取反後 \(lowbi\) 後面有幾個 \(1\) ,隨便一坨轉移一下就好了。。。
滑稽。。。其實**還是很好理解的:
#includeusing namespace std;
int bit,n;
const int n=(1<<9)+5,k=10,inf=1e9;
int a[n][n],f[n][n];
// f[i][j]表示前k-1位已經放好,上一位編號是j的最小花費
inline int dfs(int k,int num)
int tmp=(1<>bit)
for(int i=0;if[k][num]=min(f[k][num],a[num][tmp_r+i]+dfs(k+1,tmp_r+i));
return f[k][num];
}int main()
模擬賽 circle 題解
題意 有n個數,問有多少個x,x leq t 滿足這n個數分別 x後,異或和為s。每個數小於 2 m 數字dp。由於是加法,需要記錄進製,因此從低位到高位dp。只要記錄下有幾個進製,就可以根據這n的數的大小知道究竟是哪幾個進製了。設 dp i,j,0 1 表示考慮到第i位,有j個進製,與t的大小關係...
模擬賽2 題解
這次模擬賽最後一道是提答題,就不寫題解了。orz這題 emmm,我無話可說。小範圍記憶化,大範圍遞迴求解 複雜度 o k sqrt 記 f i,j 表示前 j 個數中不被 a i,a dots,a n 整除的個數,答案即為 f 1,n 狀態轉移方程為 f i,j f i 1,j f i 1,j a ...
2020 10 08 模擬賽 題解
期望100 實際100 老師說是結論題。其實可以直接打表,t i 表示0 63中有t i 對數與起來等於i,然後乘法原理即可。沒什麼難度。include include using namespace std const int maxn 100005 const int mod 1e9 7 cha...