1. 程式人生 > 其它 >ZJOI 2019 題目選做

ZJOI 2019 題目選做

省選前能多做一些就是一些了吧……

正在持續更新咕咕咕咕中。

LOJ3042「ZJOI2019」麻將

今天,可憐想要打麻將,但是她的朋友們都去下自走棋了,因此可憐只能自己一個人打。可憐找了一套特殊的麻將,它有 \(n(n \ge 5)\) 種不同的牌,大小分別為 \(1\)\(n\),每種牌都有 \(4\) 張。
定義面子為三張大小相同或者大小相鄰的麻將牌,即大小形如 \(i, i, i(1 \le i \le n)\) 或者 \(i, i + 1, i + 2(1 \le i \le n − 2)\)。定義對子為兩張大小相同的麻將牌,即大小形如 \(i, i(1 \le i \le n)\)
定義一個麻將牌集合 \(S\)

是胡的當且僅當它的大小為 \(14\) 且滿足下面兩個條件中的至少一個:

  • \(S\) 可以被劃分成五個集合 \(S_1\)\(S_5\)。其中 \(S_1\) 為對子,\(S_2\)\(S_5\) 為面子。
  • \(S\) 可以被劃分成七個集合 \(S_1\)\(S_7\),它們都是對子,且對應的大小兩兩不同

可憐先摸出了 \(13\) 張牌,並把剩下的 \(4n − 13\) 張牌隨機打亂。打亂是等概率隨機的,即所有 \((4n − 13)!\) 種排列都等概率出現。
對於一個排列 \(P\),可憐定義 \(S_i\) 為可憐事先摸出的 \(13\) 張牌加上 \(P\)

中的前 \(i\) 張牌構成的集合,定義 \(P\) 的權值為最小的 \(i\) 滿足 \(S_i\) 存在一個子集是胡的。如果你對麻將比較熟悉,不難發現 \(P\) 的權值就是理論上的最早胡牌巡目數。注意到 \(n \ge 5\) 的時候,\(S_{4n−13}\) 總是存在胡的子集的,因此 \(P\) 的權值是良定義的。
現在可憐想要訓練自己的牌效,因此她希望你能先計算出 \(P\) 的權值的期望是多少。
\(n \le 100\)


  動態規劃

  考慮怎麼判定一副牌是胡的,我們發現,將牌劃分成為對子這個是比較簡單判斷的,所以重要的是涉及面子的判斷。

  假設給了我們一個牌的個數的陣列,那麼我們從小到大去考慮每一個元素,假設考慮到了大小為 \(x\)

的牌,可以設 \(f(i, j, k)\) 表示當前是否有對子(\(i = 0 / 1\)),並且有 \(j\)\((x - 1, x)\) 的這種牌強行配對,以及還剩下 \(k\)\(x\) 牌的最多面子數。

  轉移的時候,列舉 \(d\) 表示 \(x +1\) 剩下幾張牌,然後就可以知道 \((x - 1, x, x +1)\) 構成的面子數以及新的 \((x, x + 1)\) 的對數。

  注意到 \(j, k \le 2\)(如果多了,可以之間單湊面子),於是可以把 \(f_i\) 當做一個 \(3\times 3\) 的矩陣,接著順便維護一下目前的對子數,就利用 DP 的轉移邊建出了一個“胡牌自動機”了。

  可以通過搜尋發現狀態數為 \(2092\),然後設 \(g(i, j, k)\) 表示現在考慮到了第 \(i\) 張牌,總共摸了 \(j\) 張牌,然後當前在胡牌自動機的第 \(k\) 個節點,每次轉移的時候只要不走胡牌的點即可。

  最後設 \(h_j\) 表示摸了 \(j\) 張牌,不胡的方案,那麼答案就是:

\[1 + \sum_{i = 1}^{4n - 13} \frac{h_i}{\binom{4n - 13}{i}} \]

  程式碼

LOJ3043「ZJOI2019」線段樹

九條可憐是一個喜歡資料結構的女孩子,在常見的資料結構中,可憐最喜歡的就是線段樹。

線段樹的核心是懶標記,下面是一個帶懶標記的線段樹的虛擬碼,其中 tag 陣列為懶標記:

其中函式 \(\texttt{Lson}(\text{Node})\) 表示 \(\text{Node}\) 的左兒子,\(\texttt{Rson}(\text{Node})\) 表示 \(\text{Node}\) 的右兒子。
現在可憐手上有一棵 \([1, n]\) 上的線段樹,編號為 \(1\)。這棵線段樹上的所有節點的 tag 均為 \(0\)。接下來可憐進行了 \(m\) 次操作,操作有兩種:

  • \(1\ l\ r\),假設可憐當前手上有 \(t\) 棵線段樹,可憐會把每棵線段樹複製兩份(tag 陣列也一起復制),原先編號為 \(i\) 的線段樹複製得到的兩棵編號為 \(2i − 1\)\(2i\),在複製結束後,可憐手上一共有 \(2t\) 棵線段樹。接著,可憐會對所有編號為奇數的線段樹進行一次 \(\texttt{Modify}(\text{root}, 1, n, l, r)\)
  • \(2\),可憐定義一棵線段樹的權值為它上面有多少個節點 tag\(1\)。可憐想要知道她手上所有線段樹的權值和是多少。

\(n, m \le 10^5\)


  資料結構 動態規劃

  沒怎麼看題解,按照 [ZJOI2020] 傳統藝能 的方式推了推,然後感覺寫得比較複雜/kk。

  感覺這兩個題目幾乎一樣啊。

  還是將節點分成 \(5\) 類,然後分類討論,線上段樹上每個節點維護 \((a, b, c, d)\) 表示 (都沒有,存在祖先有標記,僅自己有標記,存在祖先有標記並且自己有標記),每次修改暴力更新,然後發現只有對於 父親被包含 的點,暴力更新複雜度不對,然後根據其轉移形式打一個標記即可。

  感覺比其他題解稍微複雜,但是自我感覺看得最順眼。

  程式碼

本部落格作者:Werner_Yin(https://www.cnblogs.com/werner-yin/) ,轉載時請註明出處,謝謝支援!