Leader in Tree Land Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 169 Accepted Submission(s): 62
Problem Description Tree land has n cities, connected by n−1 roads. You can go to any city from any city. In other words, this land is a tree. The city numbered one is the root of this tree.
There are n ministers numbered from 1 to n. You will send them to n cities, one city with one minister.
Since this is a rooted tree, each city is a root of a subtree and there are n subtrees. The leader of a subtree is the minister with maximal number in this subtree. As you can see, one minister can be the leader of several subtrees.
One day all the leaders attend a meet, you find that there are exactly k ministers. You want to know how many ways to send n ministers to each city so that there are k ministers attend the meet.
Give your answer mod 1000000007.
Input Multiple test cases. In the first line there is an integer T, indicating the number of test cases. For each test case, first line contains two numbers n,k. Next n−1line describe the roads of tree land.
T=10,1≤n≤1000,1≤k≤n
Output For each test case, output one line. The output format is Case # x: ans, x is the case number,starting from 1.
Sample Input
2 3 2 1 2 1 3 10 8 2 1 3 2 4 1 5 3 6 1 7 3 8 7 9 7 10 6
Sample Output
Case #1: 4 Case #2: 316512
Source 2015 Multi-University Training Contest 7
把1到n劃分到n個結點的樹種,子樹的領導是這個子樹中權值最大的點。
求n個結點的樹種,領導為k個的情況數。
定義dp[u][i] 表示 子樹u選擇了i個領導的情況數。
假設處理了u的其他子樹, 現在計運算元樹v
那麼dp[u][i] = dp[u][j]*dp[v][i-j]
轉移的時候只從有效狀態進行轉移,那麼複雜度是O(n^2)的
對於每個跟,可以選這個點為領導有1種方案,不選它為領導有size[u]-1種方案。
因此得到兩個有效狀態。
對於一個子樹v,規模為size[v]那麼可以從沒有使用的點中選著size[v]個點,那麼
子樹v有C(size[v],size[u]-1-用過的點數)中方案分點。所以處理完dp[v]需要乘以組合數
證明如下:歸納法
對於子樹規模為K的子樹,轉移次數<=K*K
假設子樹的複雜度 滿足條件
對於u的子樹的規模分別是k1,k2,k3 (這裡假設為3個)
處理子樹k1時,轉移k1*2次即可,得到k1種有效狀態(此時0狀態其實沒用了,算k1種即可),
處理k2時,轉移的次數為k1*k2次,(背包的性質)
然後有(k1+k2)種有效狀態了,再次轉移是(k1+k2)*k3的複雜度
計算次數為 <= 2*k1 + k1*k2 + k1*k3+k2*k3 + k1*k1 + k2*k2 + k3*k3 (平方是因為子樹的計算複雜度)
<= (k1+k2+k3)*(k1+k2+k3) = k1*k1 + k2*k2 + k3*k3 + 2*k1*k2 + 2*k1*k3 + 2*k2*k3
顯然k1*k2+k1*k3+k2*k3會比k1大。
證明完畢
#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;#define maxn 1001#define ll long longll mod = 1e9+7;ll dp[maxn][maxn];vector<int>head[maxn];int size[maxn];ll res[maxn];ll C[maxn][maxn];void dfs(int u,int f){ size[u] = 1; for(int i = 0;i < head[u].size(); i++){ int v = head[u][i]; if(v == f) continue; dfs(v,u); size[u] += size[v]; } dp[u][1] = 1; dp[u][0] = size[u] - 1; int e = 1; for(int i = 0;i < head[u].size(); i++){ int v = head[u][i]; if(v == f) continue; for(int j = 0;j <= size[v] + e; j++) res[j] = 0; for(int j = 0;j <= size[v]; j++) dp[v][j] = dp[v][j]*C[size[u]-e][size[v]]%mod; for(int k = e;k >= 0; k--){ if(dp[u][k] == 0) continue; ll x = dp[u][k]; for(int j = size[v];j >=0 ; j--){ res[k+j] = (res[k+j] + dp[v][j]*x ) % mod; } } e += size[v]; for(int j = 0;j <= e; j++) dp[u][j] = res[j]; }}int main(){ memset(C,0,sizeof(C)); for(int i = 0;i < maxn; i++){ C[i][0] = 1; for(int j = 1;j <= i; j++) C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod; } int t,n,k,tt=1; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&k); memset(dp,0,sizeof(dp)); for(int i = 0;i <= n; i++) head[i].clear(); int u,v; for(int i = 1;i < n; i++){ scanf("%d%d",&u,&v); head[u].push_back(v); head[v].push_back(u); } memset(size,0,sizeof(size)); dfs(1,0); printf("Case #%d: %I64d\n",tt++,dp[1][k]); } return 0;}