AGC044 簡要題解(部分)

2022-05-19 04:36:03 字數 3564 閱讀 3760

乍一看資料範圍非常唬人,但是仔細思考一下就可以發現這樣乙個事實:

從 \(x\) 逆著執行操作回到 \(0\) 的時候,除了最後一次連續執行若干次 \(-1\) 操作直至 \(0\) 之外,其餘的時候,每兩次除法之間,用 \(\pm1\) 造成的增量只會在 \([-2, 2]\) 之間。實際上,如果下一次除數是 \(2\) 或 \(3\),那麼增量只會在 \([-1, 1]\) 之間。證明只需要考慮,如果移動路線是 \(x\rightarrow (x-1)\rightarrow (x-2)\rightarrow (\frac-1)\),那麼走 \(x\rightarrow \frac\rightarrow (\frac-1)\) 不會使答案變劣,另外兩個除數同理。

由於除法必須能夠整除才可以執行,可以發現上述過程每步最多產生 \(4\) 個後繼狀態,並且這些狀態大部分都是相同的。用堆和map維護每個狀態的最短路,搜一下可以發現狀態數大約只有 \(2\times 10^5\) 左右。

考慮維護每個位置的最短路。每次乙個人離開座位時,經過他的位置的代價 \(-1\);考慮以他的位置為起點,bfs 出所有 「以他的位置作為中轉站」 可以使最短路變短的其他位置。這麼做看起來是 \(o(n^4)\) 的,但是注意到所有被 bfs 到的點最短路都會減少 \(1\),而所有點最短路的總和是 \(o(n^3)\) 級別的。因此 bfs 的過程均攤下來是 \(o(n)\) 的。

這題 dyls 出過乙個基本上一模一樣的(

如果只有操作 \(1\),只需要用乙個置換來維護三進製表示中,最初的某個值(\(0, 1, 2\))實際上表示的是哪個值。現在加入了操作 \(2\),讓我們考慮它實際上會影響哪些數的表示方式。

首先對於所有數的最低位,都向後滾了一位,即 \(0\rightarrow 1, 1\rightarrow 2, 2\rightarrow 0\)。然後是之前的最低位實際表示是 \(2\) 的那些數,它們的次低位也要向後滾一位(加法進製),而這個過程又會產生新的加法進製。可以發現,這是個遞迴的過程,一直到最高位的時候才會發生取模從而消除進製。這提醒我們,可以用一棵三進製字典樹來維護所有數,由乙個全域性的置換來維護每個節點的每個兒子實際上表示的是哪個值。如果我們將字典樹的高低位翻轉(也就是 fft 裡的 bitrev 操作),那麼這個過程影響到的點恰好是一條鏈,只需要 \(o(n)\) 修改這條鏈上點每個值對應的兒子即可。

每次我都是恰好差一點想到正解(

丟人,我自己退出戰場(

首先考慮一下,假如字符集是0, 1怎麼做。我們可以先分別詢問乙個長度為 \(l\) 的全0串和全1串,不難發現,假如實際上有 \(x\) 個0,而實際串長為 \(|s|\),我們可以先取前 \(|s|\) 個字元中是0的位置,將剩餘位置替換,並將最後 \(l-|s|\) 個位置削除。這樣編輯距離為 \(l-x\),並且顯然不存在更小的編輯距離。也就是說,設字符集大小為 \(m\),我們可以用 \(m\) 次詢問得到每個字元的出現次數。

還是回到字符集是0, 1的情況。設0出現了 \(x\) 次,1出現了 \(y\) 次。考慮逐位確定每乙個字元是0還是1,但是我們並不能直接詢問某個位置的字元;假設我們需要判斷 \(s_1\) 是不是0,可以詢問011...11,其中後半部分有 \(y\) 個1。由於1的個數恰好夠用,這乙個0的出現並不能動搖1的地位——如果 \(s_1\) 確實是0,那麼編輯距離一定是 \(|s|-y-1\),但是如果 \(s_1\) 不是0,那麼最優的編輯距離必然是將最前面的0刪掉,再把所有的0依次插到合適的位置中去(否則至少要刪掉乙個1再把它加到這個0前面,或者修改至少兩個位置的值,不會比刪掉乙個0的代價還多)。

確定了 \(s_1\) 之後,我們考慮依次確定 \(s\) 的每個位置,可以發現,只需要令 \(s'\) 表示已確定的部分,詢問 \(s'+\)011...11即可,其中後半部分1的數量等於未確定位置的1數量。

實際上,我們上面的過程是在合併兩個字符集交集為空的子串行。

只要注意到這個事實,就會發現之前的操作並不侷限於01,只要待合併的兩個部分的字符集交集為空,這一系列的過程都沒有本質區別。

因此,設 \(\sigma\) 表示字符集大小,詢問的總次數是 \(o(\sigma+l\log_2\sigma)\) 級別的,可以通過。

實際上,usaco 有一道題(18dec platinum——balance beam)是這個題的一部分。

在 usaco 版本裡,序列並非是乙個環,到達兩個端點後遊戲會自動結束(並獲得 \(0\) 的收益),且移動一步不需要任何代價。不難發現,由於移動不需要任何代價且每一步面臨的局面是無記憶性的,只需要確定到達每個點時是否結束遊戲,就可以求出每個點的期望收益。

假設當前落腳點為 \(x\),如果 \(x\) 是結束點,顯然收益就是 \(a_x\);否則,假設左、右最近的結束點分別是 \(l, r\),不難發現,從 \(x\) 隨機遊走,走到 \(l, r\) 的概率分別是 \(\frac\) 和 \(\frac\)。因此,在 \(x\) 點的期望收益就是 \(\frac a_l+\frac a_r\)。實際上,如果將每個停止點的位置作為橫座標,收益作為縱座標的話,每個非停止點 \(i\) 的期望收益恰好就是兩端最近的停止點確定的一次函式,在 \(x=i\) 時的縱座標。

這個時候,就可以發現,由於凸包內任意選兩個點,連出的線段都不會在凸包外,只需要將所有點 \((i, a_i)\) 建立乙個上凸殼,取凸殼上的點作為停止點即可。

回到原題,發現序列變成了環,且每走一步都會付出不同的代價。環的限制其實很好解決:注意到玩家走到任意乙個最大值時必然不會再走,可以在最大值處將環斷成序列。但是如果每走一步都要付出代價,就無法套用上面的凸包。

先列出原始的式子:\(f_i=\max(a_i, \frac+f_}-b_i)\),而我們希望的式子是 \(g_i=\max(a'_i, \frac+g_})\),於是考慮構造出乙個 \(c_i=f_i-g_i\),再由 \(c_i\) 和 \(a_i\) 構造出 \(a'_i\),就可以用上面的凸包方法求出所有的 \(g_i\) 了。考慮 \(g_i=f_i-c_i=\max(a_i-c_i, \frac+f_}-b_i-c_i)=\max(a_i-c_i, \frac+c_+g_+c_}-b_i-c_i)\)。這時候注意到,如果 \(\frac+c_}-b_i-c_i=0\),那麼令 \(a'_i=a_i-c_i\) 的話,就恰好滿足上面的條件。至於 \(c_i\) 的求法,注意到 \(c_i\) 有 \(n+1\) 個,但只有 \(n-1\) 個方程,因此可以直接令 \(c_0=c_n=0\),然後就可以兩邊遞推求出 \(c_i\) 了。

可能是我寫法問題,但是本題略微卡精度,需要long double才能通過。

AGC 049 部分簡要題解

nmd 差1分鐘過 e,真就老年選手不配進第一頁 ll 計算每個點的貢獻,做完了 includeusing namespace std typedef long long ll const int n 110 string s n int n bitsettow n int main int s n...

AGC047 簡要題解

注意精度問題即可 建顆 trie 樹搞一搞即可 考慮用原根解決此問題,乘法變為了加法,因此用桶記錄一下 fft 即可 觀察題目性質容易發現樹高事 log n 的,即使是暴力列舉第一棵樹最淺的點複雜度也正確。因此就暴力列舉,那麼一條合法的路徑肯定是分別走向兩個兒子的,考慮從左兒子走到第二棵樹每個節點的...

AGC025簡要題解

b rgb coloring 一道簡單題,列舉即可。c interval game 考慮可以進行的操作只有兩種,即左拉和右拉,連續進行兩次相同的操作是沒有用的。左拉時肯定會選擇右端點盡量小的,右拉選擇左端點盡量大的,所以排序之後貪心即可。d choosing points 首先證明對於所有 d 假設...