「優質題解」排隊買票

這道題的地址,想嘗試的小夥伴可以來試哦:

https://www.dotcpp.com/oj/problem1163.html

思路:

1. N = K

考慮當 N = K 時的特殊情況,即有 2N 個小孩,其中N個小孩帶的錢為1元,另外N個小孩帶的錢為2元。

此時可利用卡特蘭數的通項公式簡單求解:

當然,由於題目中說小孩交換位置算一種新的排隊方式,所以還要再乘上 n 的全排列(乘兩遍)。

2. N > K

當 N > K 時,無法直接用卡特蘭數求解,這時我們可以換一種思維:無法直接求出合法的排隊方式數,那就先求出非法的排隊方式數,再用總的排隊方式數減去,即得合法的排隊方式數:

總的排隊方式數:

很簡單:一共 M 人排隊,有 M!(M 的全排列)種排隊方式。

非法的排隊方式數:

我們考慮一下非法的排隊方式有什麼特徵:
  • (1) 前 2P 個小孩組成一個合法的排隊,且持有 1 元的小孩和持有 2 元的小孩數量相等,皆為 P。(P = 0, 1, 2……)
  • (2) 第 2P + 1 個小孩持有 2 元。
證明:
  • (1) 證明滿足此特徵的排隊均非法: 顯然,由於前 2P 個小孩使得售票員「收支平衡」,第 2P + 1 個小孩到來時剛好無錢可找,所以是非法的排隊。
  • (2) 證明非法的排隊均滿足此特徵:
    • 當非法隊伍長度為奇數時: <a> 如果除去最後一個孩子仍是非法排隊: 去掉隊尾一個小孩,進行隊伍長度為偶數時的論證。 <b> 如果除去最後一個孩子變為合法排隊: ※ 則最後一個孩子一定持有 2 元。(一個合法排隊加上一個持有 1 元的小孩並不會變成非法排隊) ※ 此合法隊列中持有 1 元的小孩和持有 2 元的小孩數量相等。(若持有 2 元的小孩數量較多,此隊列一定是非法隊列;若持有 1 元的小孩較多,則即便最後一個小孩持有 2 元也不會變為非法隊列)
    • 當非法隊伍長度為偶數時: 則總是存在這樣一個正整數 Q(2Q <= 隊列長度),使得前 2Q 個小孩構成一非法排隊(換言之,如果對於任意的正整數 Q,總有:前 2Q 個小孩構成的隊列是合法的,那麼這個隊列本身也是合法的。) 於是可以對前 2Q 個小孩的非法隊列進行遞歸論證,直到找不到這樣的 Q 時,去除隊尾一個小孩,進行奇數隊伍論證。
計算公式:

非法排隊特徵:

(1) 前 2P 個小孩組成一個合法的排隊,且持有 1 元的小孩和持有 2 元的小孩數量相等,皆為 P。(P = 0, 1, 2……)

(2) 第 2P + 1 個小孩持有 2 元。

於是我們可以把非法排隊分為 3 部分:

  • 前 2P 個小孩
  • 第 2P + 1 個小孩
  • 剩下的小孩,假設共 R 個(R = M – 2P – 1)

前 2P 個小孩組成一個合法排隊,且滿足:M』 = 2P,N』 = K』 = P。 於是排隊數可以用卡特蘭數計算。 第 2P + 1 個小孩要持有 2 元,由於前 2P 個小孩中已經用掉 P 個持有 2 元的小孩,此處還有 K – P 種選擇。 最後 R 個小孩的排隊方式不影響整體性質,所以全排列。

公式為:

合法的排隊方式數:

合法的排隊方法數就等於總的方法數減去非法的方法數:

程式碼實現: