2018 Wannafly summer camp Day3-- Travel (思維 組合數取模)
阿新 • • 發佈:2018-12-13
題目大意:
魔方國有n座城市,編號為。城市之間通過n-1條無向道路連線,形成一個樹形結構。瀾瀾打算在魔方國進行m次旅遊,每次遊覽至少一座城市。為了方便,每次旅遊遊覽的城市必須是連通的。此外,瀾瀾希望遊覽所有城市恰好一次。 瀾瀾想知道有多少種旅遊方案滿足條件,兩個方案不同當且僅當存在某一次旅遊遊覽了不同的城市。瀾瀾不會數數,所以只好讓你來幫他數方案。
題解:
第一次見到披著樹形結構的外衣卻與樹完全不相干的題。
首先給了n個點,n-1條邊,那麼肯定是一棵樹。進行m次旅行,每個點都要經過且只能經過一次,那就是用m條邊將n個點分為m段,這裡就是隔板法的思想,劃分數就是
(將n個點劃分為m段,就是在n-1個空中插入m-1個板)。-----------------------------------------------------------------------------------------------------------------------------------------------------------------
在網上也看了一些題解,都是一個版本的,感覺並沒有說的很清楚。我認為本題應該是劃分點而不是劃分邊,即劃分n個點而不是n-1條邊,因為並不一定所有點都在一條邊上。
比如這個圖,將6個點的樹劃分為3段,那麼左邊那一段是不可能通過一次旅行來走完的。所以劃分邊不行,需要劃分點。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib> #define mod 1000000007 using namespace std; typedef long long ll; #define maxn 1000010 int t, n, m, ta, tb; ll c[maxn]; long long pow_mod(long long a,long long n,long long m)//a^n mod m { long long res=1; while(n>0) { if(n&1==1) res=res*a%m; a=a*a%m; n>>=1; } return res; } //記得在最後輸出結果的時候再模m一次 void init()//先打出階乘,節省時間 { c[1] = 1; for (int i = 2; i <= maxn; i++) c[i] = c[i - 1] * i%mod; } ll C(ll n, ll m) { return c[n] * pow_mod(c[m] * c[n - m] % mod, mod - 2, mod) % mod; } int main() { init(); int T,x,y; cin>>T; while(T--) { cin>>n>>m; for(int i = 0; i < n - 1; i++) cin>>x>>y; if(m == 1) { puts("1"); continue; } ll ans = C(n, m); ans = (ans*c[m]) % mod; cout << ans << endl; } return 0; }