JOI2020

這一切還要從一隻蝙蝠說起


只不過是長的領帶

先考慮\(n\)個人和\(n\)個領帶的匹配,對於權值最大的領帶,顯然和權值最大的人匹配更優,因爲如果拿權值最大領帶和別的人匹配,然後權值最大的人和小點的領帶匹配,這樣的貢獻顯然不會更少,所以最優匹配其實就是分別對兩者排序後依次匹配

現在要求去掉每一個領帶後剩下領帶匹配的權值,我們先把領帶按大小排序,然後對於去掉第\(i\)大的領帶的情況,更小的\(i-1\)個領帶會依次跟權值最小的\(i-1\)個人匹配,更大的\(n+1-i\)個會依次和後面\(n+1-i\)個人匹配,所以預處理前\(i\)個領帶和人的匹配最大值和後\(i\)個領帶和人的匹配最大值就可以做到每次詢問\(O(1)\)

JJOOII2

這裏可以枚舉刪掉的前綴長度,然後相當於要選一個接着這個前綴的最短子段,滿足依次有\(k\)\(J\),\(k\)\(O\),\(k\)\(I\),我們可以維護三個指針,分別表示含有\(k\)\(J\)子段的最小右端點,有\(k\)\(J,\)\(k\)\(O\)子段的最小右端點,有\(k\)\(J\),\(k\)\(O\),\(k\)\(I\)的最小右端點,並且預處理每種字符出現次數前綴和就可以一步步往後移指針.注意到每次移動前綴的時候這三個指針都是單調向後移動,複雜度\(O(n)\)

集郵比賽3

斷環成鏈後有個顯然的dp是\(f_{i,j,k,0/1}\)表示當前遍歷過了\([i,j]\)裏面的點,所用時間爲\(k\),當前在\(i\)或者是\(j\),的最大集郵數,轉移可以做到\(O(1)\).但是所有時間數值比較大,同時可以發現郵票總數爲\(O(n)\)級別,所以把狀態的\(k\)改爲當前集郵數,把狀態的值改爲用的最少時間即可,同樣可以\(O(1)\)轉移

奧運公交

\(\small\text{這個菜字就寫在我的臉上...}\)

先建出以\(1\)爲根,以\(n\)爲根的最短路樹,然後在反圖上再建以\(1\)爲根,以\(n\)爲根的最短路樹,這個時候再枚舉一條要翻的邊,如果這條邊沒有在任何一棵最短路樹裏出現,那麼之前的最短路還是可以用的,我們就只要討論新的最短路是否經過翻過來的邊,再用最短路樹的信息更新答案即可;否則,由於這樣的邊數量是\(O(n)\)級別的,可以刪掉這條邊後跑最短路,這裏複雜度爲\(O(n(n^2+m))=O(n^3+nm)\)

火災

先以位置爲橫軸,時刻爲數軸,寫出一個矩陣,每一位分別對應每個時刻每個位置的權值.然後考慮每個位置對這裏權值變化的貢獻

對於一個位置\(i\),它可以在之後的一段時間內覆蓋後面一段權值更小的位置,直到碰到權值\(\ge\)它的位置後停止,設這個停止位置爲\(nt_i\)(這個位置顯然是\(i\)後面第一個權值不小於\(i\)的位置),那麼在\(t\in[1,nt_i-i)\)時刻第\(i+t\)位置的權值會被覆蓋爲\(s_i\).我們把上述的覆蓋看做是先減去原來的值,然後加上現在的值,那麼也就是\(i\)號位會在\(t\)時刻給\(i+t\)號位加上\(s_i\)

然後考慮減權值部分.一個位置的權值顯然是被往前走第一個權值更大的位置覆蓋,記此位置爲\(ft_i\),那麼從\(ft_i\)上的權值覆蓋到\(i\)開始,之後一段時間還會去依次覆蓋後面的一些位置,直到到\(nt_i\)這一位沒有\(i\)覆蓋的貢獻.形式化的講,就是在\(t\in[i-ft_i,nt_i-ft_i)\)時刻,第\(i+t-(i-ft_i)\)位會減去原有權值,即\(s_i\)

可以發現上述的貢獻總數是在\(O(n)\)級別的.對於一個詢問\((t,l,r)\),先套路的拆成是\((t,1,r)-(t,1,l-1)\).然後現在一個\((t,1,i)\)就是在縱座標爲\(t\)的一排裏前\(i\)位的和.然後我們把一開始的矩陣的相鄰兩排前後差分,就可以發現對於前面討論到的一種貢獻在差分後的矩陣上是一段斜着的線段.另外現在的每個詢問也就是對應區間的初值加一個前綴的矩陣的和

對於一個斜的線段,起始點和終止點分別爲\((x,y),(x',y')\),我們可以看成是一個正貢獻點\((x,y)\)和一個負貢獻點\((x'+1,y'+1)\)往右上方的貢獻

對一個貢獻點\((x,y)\),設其權值爲\(w\),對詢問\((t,1,i)(i\ge x,t\ge y)\)的貢獻爲\(w*\min(t-y+1,i-x+1)\).那麼可以發現取出\((i,t)\)點所在的左下-右上對角線後,取到\(t-y+1\)這一部分的貢獻點全在對角線上方,反之全在對角線下方.所以對於對角線進行掃描線,先把所有貢獻點放在對角線下方的貢獻裏,然後掃到當前對角線後把線上的貢獻點貢獻一到對角線上方的貢獻裏;對於端點經過當前對角線的詢問,只要查詢前綴\(i\)的下方貢獻以及前綴\(t\)的上方貢獻即可.我們把貢獻記在樹狀數組裏,如果樹狀數組上第\(i\)爲權值爲\(w_i\),那麼對詢問前綴\(n\)的貢獻爲\((n-i+1)w_i\),把貢獻拆爲\((n+1)w_i\)\(-iw_i\)兩部分,那麼樹狀數組分別維護\(\sum w_i,\sum iw_i\)即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章