題解 LOJ3265 3266 3267 USACO 2020.2 Platinum(全)


題解 loj3265 3266 3267 USACO 2020.2 Platinum(全)

loj3265 「USACO 2020.2 Platinum」Delegation

題目鏈接


因為是最大化最小值,考慮二分答案。

設當前二分的答案為\(K\)。則要判斷是否有一種划分方式,使得每條鏈的長度都至少為\(K\)

不妨以\(1\)為根,對整棵樹dfs。記\(fa(u)\)\(u\)的父親節點。dfs(u)函數求出一個值\(f(u)\),或判斷在當前的\(K\)下無解。有解時,我們把\(u\)的子樹划分為若干條長度\(\geq K\)的鏈,並選擇一條未完結的鏈(允許這條鏈長度\(<K\))覆蓋\(u\)\(fa(u)\)之間這條邊。這條鏈會被交給dfs(fa(u))繼續處理。而\(f(u)\),就是這條返回給\(fa(u)\)的鏈的最長長度。dfs(u)函數要做的,就是在保證其他每條鏈長度都\(\geq K\)的前提下,讓\(f(u)\)的長度盡可能大。

考慮dfs(u)函數的實現。先遞歸\(u\)的所有兒子,每個兒子\(v\)會帶來一條長度為\(f(v)+1\)的鏈(這個\(+1\)就是\(u,v\)之間的邊,它沒有被算在\(f(v)\)中)。把得到的這些鏈按長度排序。此時我們有兩種選擇:

  • 方案一:把所有這些鏈兩兩匹配。(如果鏈的數量是奇數,就加一條長度為\(0\)的鏈)。要求每對匹配鏈的長度和\(\geq K\)。並令\(f(u)=0\)
  • 方案二:挑出一條鏈作為\(f(u)\),讓其余的鏈兩兩匹配。如果能匹配成功,則令\(f(u)=\)這條挑出來的鏈的長度。

這里的“兩兩匹配”,我們可以做一個簡單的貪心:讓最大的鏈和最小的鏈匹配,第\(2\)大的鏈和第\(2\)小的鏈匹配......。如果存在某一對鏈的長度和\(<K\),說明匹配失敗,無法找到合法的匹配方案。

\(u=1\)時,我們顯然只能選擇方案一,即把所有鏈都匹配起來。否則無解。

\(u\neq 1\)時,本着讓\(f(u)\)盡可能大的原則,我們優先考慮方案二。如果無法實現方案二,再考慮方案一是否可行。若也不可行,則無解。

現在的問題是,如果選擇方案二,我們該如何在保證其它鏈能夠成功匹配的前提下,挑出一條盡可能長的鏈作為\(f(u)\)呢?考慮兩條長度分別為\(x,y\)的鏈,若\(x<y\),則若挑出\(y\)這條鏈后其它鏈能夠成功匹配,挑出\(x\)后其他鏈也一定能成功匹配(這相當於把匹配中的\(x\)換成\(y\),有一條鏈變得更長了,匹配結果不會變差)。故可以二分把那條鏈作為\(f(u)\),判斷是否可行即可。

時間復雜度\(O(n\log^2n)\)

參考代碼

loj3266 「USACO 2020.2 Platinum」Equilateral Triangles

題目鏈接


圖片來源:洛谷用戶:ix35

觀察一個曼哈頓等邊三角形:

紅線、藍線分別是\(BC,AC\)的曼哈頓距離。

把線段平移,得到下圖:

此時,\(BC\)的曼哈頓距離是\(\color{red}{\text{紅}}\)\(+\)\(\color{green}{\text{綠}}\)\(AC\)\(\color{blue}{\text{藍}}\)\(+\)\(\color{green}{\text{綠}}\),於是我們可以得到:\(\color{red}{\text{紅}}\)\(+\)\(\color{green}{\text{綠}}\)\(=\)\(\color{blue}{\text{藍}}\)\(+\)\(\color{green}{\text{綠}}\),所以\(\color{red}{\text{紅}}\)\(=\)\(\color{blue}{\text{藍}}\)。同理可知:\(AO=BO=CO\)(曼哈頓距離)。也就是說,\(O\)\(\Delta ABC\)在曼哈頓距離意義上的“外心”。

考慮枚舉這個外心\(O\),再枚舉\(O\)\(A,B\)的距離\(r\)。大力討論\(A,B\)所在的象限(四種情況)。此時\(A,B\)的位置就已經確定了。考慮\(C\)。首先\(C\)一定在和\(A,B\)相反的象限,且\(OC=r\)。可以發現這樣的\(C\)一定在一條斜\(45^{\circ}\)角的線上(即平行於矩形某條對角線的線)。對每條這樣的斜線做前綴和即可\(O(1)\)查詢出\(C\)的數量。

時間復雜度\(O(n^3)\)

參考代碼

loj3267 「USACO 2020.2 Platinum」Help Yourself

題目鏈接


把所有線段按左端點排序。設\(dp_0[i][r]\)表示考慮了前\(i\)條線段,最大右端點在\(r\)時,有多少滿足條件的線段子集;\(dp_1[i][r]\)表示此時所有滿足條件的線段子集,每個線段子集的的連通塊數之和;\(dp_2[i][r]\)表示此時所有滿足條件的線段子集,每個線段子集的的連通塊數的平方,之和......。

一般地,定義\(dp_k[i][r]\)表示考慮了前\(i\)條線段,最大右端點在\(r\)時,所有滿足條件的線段子集,每個線段子集的並的連通塊數的\(k\)次方之和(\(0\leq k\leq K\))。設對於一個線段集合\(s\)\(\operatorname{maxendpos}(s)\)表示\(s\)中所有線段的最大右端點,\(cnt(s)\)表示\(s\)的連通塊數。則:

\[dp_k[i][r]=\sum_{s\subseteq[i],\ \operatorname{maxendpos}(s)=r}cnt(s)^k \]

考慮新加入一個線段\(i\)。從\(dp[i-1][j]\)轉移到\(dp[i][?]\)。分三種情況討論:

  • \(j<l_i\),此時加入線段\(i\)會使右端點變為\(r_i\),且連通塊數\(+1\)
  • \(l_i\leq j\leq r_i\),此時加入線段\(i\)會使右端點變為\(r_i\),且連通塊數不變。
  • \(j>r_i\),此時加入線段\(i\)既不改變右端點也不改變連通塊數。

發現問題主要在於連通塊數\(+1\)時的轉移不好處理。考慮現在有一\(dp_k[i][j]\),把它的連通塊數\(+1\),看它的值會如何變化:

\[trans(dp_k[i][j])=\sum_{s}(cnt(s)+1)^k=\sum_s\sum_{t=0}^{k}{k\choose t}cnt(s)^t=\sum_{t=0}^{k}{k\choose t}dp_t[i][j] \]

由此,此時再考慮\(dp_k[i][?]\)的轉移式。初始時,令每個\(dp_k[i][j]=dp_k[i-1][j]\),表示在線段集合中不選線段\(i\)的情況。然后考慮選線段\(i\)的情況:

\[dp_k[i][r_i]+=\sum_{j=0}^{l_i-1}trans(dp_k[i-1][j])+\sum_{j=l_i}^{r_i}dp_k[i-1][j]\\ dp_k[i][x]+=dp_k[i-1][x]\quad(x>r_i) \]

其中\(trans(dp_k[i-1][j])\)可以\(O(K)\)求。故時間復雜度為\(O(n^2K^2)\)

考慮優化。

首先,\(\sum_jtrans(dp_k[i-1][j])\)就等於\(trans(\sum_jdp_k[i-1][j])\)。因為我們在推\(trans\)時並沒有用到\(j\)具體的值,只是用\(i,j\)來表示了一堆“線段的集合”。把這些集合先並起來(作為一個更大的集合),再轉移也是一樣的。

根據套路,不難想到用線段樹去維護所有的\(j\)。線段樹上,設一個節點所代表的區間為\([l,r]\)。我們在這個節點上存\(K+1\)個值,分別為:\((\sum_{j=l}^rdp_0[i][j]),(\sum_{j=l}^rdp_1[i][j]),\dots,(\sum_{j=l}^rdp_K[i][j])\)

則從\(i-1\)\(i\)的轉移相當於:

  • \(r_i\)這個位置執行線段樹單點加操作,讓它的值\(+trans(\sum_{j=0}^{l_i-1}dp_k[i-1][j])\)。其中求\((\sum_jdp_k[i-1][j])\)要用到線段樹區間求和
  • \(r_i\)這個位置執行線段樹單點加操作,讓它的值\(+(\sum_{j=l_i}^{r_i}dp_k[i-1][j])\)
  • 對線段樹\(r_i+1\sim 2n\)這些位置執行區間乘操作,全部\(\times2\)

注意,所有的查詢操作要在修改操作之前進行。這樣查到的才是\(dp_k[i-1]\)的值。

時間復雜度\(O(nK^2+n\log nK)\)

參考代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM