【nyoj-127】星際之門(一)(Cayley公式 / Prufer序列)
星際之門(一)
時間限制:3000 ms | 記憶體限制:65535 KB
難度:3
描述
公元3000年,子虛帝國統領著N個星系,原先它們是靠近光束飛船來進行旅行的,近來,X博士發明了星際之門,它利用蟲洞技術,一條蟲洞可以連通任意的兩個星系,使人們不必再待待便可立刻到達目的地。
帝國皇帝認為這種發明很給力,決定用星際之門把自己統治的各個星系連結在一起。
可以證明,修建N-1條蟲洞就可以把這N個星系連結起來。
現在,問題來了,皇帝想知道有多少種修建方案可以把這N個星系用N-1條蟲洞連結起來?
輸入
第一行輸入一個整數T,表示測試資料的組數(T<=100)
每組測試資料只有一行,該行只有一個整數N,表示有N個星系。(2<=N<=1000000)
輸出
對於每組測試資料輸出一個整數,表示滿足題意的修建的方案的個數。輸出結果可能很大,請輸出修建方案數對10003取餘之後的結果。
樣例輸入
2
3
4
樣例輸出
3
16
思路:
題意很簡單,就是如果有n個點,能生成多少種不同的樹,這道題目實際就是考察Purfer序列應用(Purfer序列的部落格),一顆n個結點的樹,轉成一個Purfer序列後,序列的元素有n-2個,而一棵樹和一種序列是一一對應的(一棵n個節點的無根樹唯一地對應了一個長度為n-2的數列),因此要問能產生多少樹,只要看序列的種類數,序列有n-2個位置,每個位置上 的元素有n種(序列中是允許有重複元素的),因此序列的種類即不同的樹的種類有
Cayley定理:有n個節點的完全圖的生成樹的數量是,或者說n個節點的帶標號的無根樹有個。
Prufer編碼:給定一棵帶標號的無根樹,找出編號最小的葉子節點,寫下與它相鄰的節點的編號,然後刪掉這個葉子節點。反覆執行這個操作直到只剩兩個節點為止。
一個有趣的推廣是,n個節點的度依次為D1, D2, …, Dn的無根樹共有(n-2)! / [ (D1-1)!(D2-1)!..(Dn-1)! ]個,因為此時Prüfer編碼中的數字i恰好出現Di-1次。(轉自此部落格)
ac程式碼:
#include<stdio.h> #include<string.h> #include<queue> #include<set> #include<iostream> #include<map> #include<stack> #include<cmath> #include<algorithm> #define ll long long #define mod 10003 #define eps 1e-8 using namespace std; ll qsm(ll a,ll b) { ll t=1; while(b) { if(b&1) { t=(t*a)%mod; } a=(a*a)%mod; b>>=1; } return t%mod; } int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); printf("%lld\n",qsm(n,n-2)); } return 0; }