《训练指南》——6.10
Uva11174:
? 村民排隊:村子里現在有n(1≤n≤40000)個人,有多少種方式可以把它們排成一列,使得沒有人站在他父親的前面(有些人的父親可能不在村子里)?輸入n和每個人的父親編號,輸出方案總數除以1000000007的余數。
? 分析:首先我們應該能夠看到的是,這種有關家庭關系的圖,需要借助基本的一個數據結構——樹,但是這里由于各個祖先不同,會形成森林,但是為了更好處理,我們將森林中的根節點的上面構造一個虛擬根,記作v0,這樣就形成了一棵樹。
? 我們設f[i]是以節點vi為根,得到的排列情況書,即f[0]就是這道題目的答案。
? 那么我們現在來考察f[0]究竟怎么計算,這里用到基本的計數原理。我們假設虛擬根v0下有k個兒子v1、v2、v3…vk,相當于有k個家族,則我們可以通過如下的步驟得到f[0]:
(i)???????????????? 我們將每個家族的人視為一樣的元素.
(ii)?????????????? 得到排列數之后再乘上這個家族符合要求的排列數.
這里記s[i]是第i個家族的人數,也就是說以vi為根的所有節點的和(包括vi自己),那么完成第一個步驟,我們得到的方法數是
??????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ?
? 而完成第二個步驟,結合分步乘法原理,應該是如下的式子:
?????????????????????????????????????????????
??????????????????????????????????????????????????? ?
? 這樣我們便得到了一個關于f[n]的遞推式,如下:
?????????????
??? 其中k是v0的兒子個數,如果我們設置一個數組son[i]記錄vi的兒子兒子數,ci表示節點的i個兒子在樹結構中的序號,因此我們會得到更加具有普遍性的遞推式子:
???????????
??? 那么現在將②迭代到①當中,會發現一直遞推下去,再考慮對于葉節點vj,有f[j]? = 1,因此我們能夠得到如下的線性表達式:
????????????
???????????????????????? ?
? 那么基于這個線性表達式,接下來我們需要考慮的事情就很明了了:
? 問題一:如何基于樹結構找到s[i]呢,這是最基本的數據結構的問題。
? 問題二:題目要求輸出f[0] % mod,而根據數論當中同余運算的性質,涉及出發應該借助逆元,而結合mod的大小和s[i]的取值,有gcd(mod , s[i]),我們也是能夠得到s[i]在關于mod下一定存在逆元的。
? 總結一下,這道題目還是一道非常好的題目的,它涉及了組合計數的基本原理、遞推、整理數學公式、基本樹形數據結構和數論當中的逆元,是一道非常綜合的題目。這里筆者由于臨近考試周時間緊張的原因,在如何編碼實現計算s[i]和求解逆元上先不做討論,以后有時間了再補充。
轉載于:https://www.cnblogs.com/rhythmic/p/5576567.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的《训练指南》——6.10的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ADO.NET封装的SqlHelper
- 下一篇: 第十五周学习进度