BZOJ P1211 HNOI2004 樹的計數

2021-07-29 11:08:59 字數 1400 閱讀 8082

第一次學prufer數列相關,一開始覺得可能可以樹形dp但發現複雜度大的我無法想象

然後發現是prufer數列

一種生成prufer序列的方法是迭代刪點,直到原圖僅剩兩個點。對於一棵頂點已經經過編號的樹t,頂點的編號為,在第i步時,移去所有葉子節點(度為1的頂點)中標號最小的頂點和相連的邊,並把與它相鄰的點的編號加入prufer序列中,重複以上步驟直到原圖僅剩2個頂點。

例子prufer數列

以右邊的樹為例子,首先在所有葉子節點中編號最小的點是2,和它相鄰的點的編號是3,將3加入序列並刪除編號為2的點。接下來刪除的點是4,5被加入序列,然後刪除5,1被加入序列,1被刪除,3被加入序列,此時原圖僅剩兩個點(即3和6),prufer序列構建完成,為

設為一棵有n個節點的樹的prufer序列,另建乙個集合g含有元素,找出集合中最小的未在prufer序列中出現過的數,將該點與prufer序列中首項連一條邊,並將該點和prufer序列首項刪除,重複操作n-2次,將集合中剩餘的兩個點之間連邊即可。

例子仍為上面的樹,prufer序列為,開始時g=,未出現的編號最小的點是2,將2和3連邊,並刪去prufer序列首項和g中的2。接下來連的邊為,,,此時集合g中僅剩3和6,在3和6之間連邊,原樹恢復

然後我們發現乙個prufer數列非常nice的性質:

就是乙個節點在prufer數列中出現的次數是這個節點度數減一

很好證明,如果這個點是葉子節點那麼不會出現的啊,即為0

如果不是葉子節點,那麼每一次他的葉子節點被刪時,他的度數減一,減到為一時,即為葉子節點了,所以出現次數為度數減一

然後排列組合一算就可以了

發現題目中n很小,直接質因數分解一下就可以了,不需要高精度

然後的話,通過prufer的定義,我們會發現,到最後prufer數列的中的數一共有n-2個

至於prufer數列的個數一共有n-2的證明我補上一下,其實非常顯然,我每加乙個點必須先刪掉乙個點

那麼非常顯然的是我一共要刪n-2個點,那麼prufer序列中的數一共有n-2個

那麼所有的數的度數減一的和不為n-2就沒有方案了

下面是**

#include#includeusing namespace std;

int n,tot,p[2][151],x;

long long ans(1);

void cal(int x,int k)

if(x==1)

}}//直接把數字質因數分解記錄進陣列裡面

long long qpow(int x,int y)else

return fanhui;

}}//快速冪

int main()

}//當x>2時,拆開記錄乙個p陣列中

if(x>1)//記所有點的度數減一然後加起來

}if(n==1)

}//算答案

cout<

bzoj 1211 HNOI2004 樹的計數

題意 給出每個節點的度數,問有多少棵樹滿足這些度數。題解 pr fer序列 組合數學 pr fer序列是由標號樹產生的唯一數列。生成方法 一棵樹要得到普呂弗序列,方法是逐次去掉樹的頂點,直到剩下兩個頂點。考慮樹t,其頂點為。在第i步,去掉標號最小的葉,並把普呂弗序列的第i項設為這葉的鄰頂點的標號。序...

BZOJ 1211 HNOI2004 樹的計數

今天早上由於剩下的非許可權題實在是太難了。於是學了一下新東西續命。直接prufer序列排列組合就好了。注意各種0的情況 code include include typedef long long ll const ll n 155 ll n ll a n ll pri n ll tot ll cn...

bzoj1211 HNOI2004 樹的計數

題目傳送門 解法 prufer數列。有這麼三個性質 乙個prufer數列與乙個無根樹一一對應。乙個n個節點的無根樹的prufer數列長度為n 2。乙個點的度數等於他在prufer數列裡面出現的次數 1。第三個性質這樣證明 首先需要了解prufer序列如何構造 看這裡在prufer數列中,如果乙個點出...