1. 程式人生 > >【BZOJ】4446: [Scoi2015]小凸玩密室 倍增+樹形DP

【BZOJ】4446: [Scoi2015]小凸玩密室 倍增+樹形DP

題解

倍增+DP好題。這道題的DP太神了!

感覺上這道題怎麼DP向後的狀態,或向前的狀態都非常不好做,從Chen’s Blog學到了DP的新姿勢

非常關鍵的一點:這是一顆完全二叉樹。很多DP的優化方法都由此而來。

觀察點燈的過程:

(1) 點亮一個點 (2) 選擇其一個子節點遞迴下去,遞迴完畢則該子節點子樹全部點亮(最後一個被點亮的必然是某個該子樹內的葉子節點) (3) 再遞迴另一子樹 (4) 該子樹已全部點亮,回溯其父節點 (5) 繼續操作,直到整棵樹都被點亮

由此過程受到啟發:

  1. 無法有效列舉每一點是由其兄弟節點子樹內哪個葉子轉移而來
  2. 但可以列舉葉子轉移到其某一級祖先的兄弟節點/或某一級祖先(注意這是一顆完全二叉樹,層數是嚴格
    logn
    的)的最少花費。
  3. 轉移到某一級祖先的兄弟節點的情況表示過程(3),轉移到某一級祖先的情況表示過程(4)

現在可以列出轉移陣列f[i][j][2]了,設lci,rci分別表示節點i的左右兒子,節點i的第j個祖先為fa[i][j](這裡的第j個祖先表示第j靠近該點的祖先),節點i的第j個祖先的不為i祖先的子節點(f[i][j1]的兄弟)為li[i][j]

  • f[i][j][0]表示以節點i為根的子樹全部被點亮之後再去點亮fa[i][j]的最小花費

  • f[i][j][1]表示以節點i為根的子樹全部被點亮之後再去點亮li[i][j]的最小花費

f[i][j][0/1]均假設i為起點(點亮i花費為0)。轉移是O(1)的,分類討論一下:

  • i是葉子節點。 f[i][j][0]=dist(i,fa[j][j])×afa[i][j]f[i][j][1]=dist(i,li[i][j])×ali[i][j]

  • i只有左兒子,只能走左兒子。

    f[i][j][0]=f[lci][j+1][0]+dist(i,lci)×alci