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
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 .
T=10,1≤n≤1000,1≤k≤n
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
Case #1: 4 Case #2: 316512
求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 long
ll 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;
}