题意:给出n个点的树,问它的子树有多少和它有相同的中心。树中心是指使得距离树最远的点最近的点,中心有可能有1个或2个。
思路:感觉这题好难做。。。首先是要求中心,这个还是很好做的,直接树dp就能解决,然后要分中心个数是1个或2个这两种情况。首先求一下dp[i][j],这个表示结点i的子树中,距离i不超过j的方案数。这样对于结点i,想要求出长度为k的子树的个数就可以用dp[i][k]-dp[i][k-1]求出。接下来,如果中心的个数为2,那么很简单,只要令这两个中心的子树最长的距离相等就可以,枚举一下距离就行了。比较麻烦的是中心个数为1个的情况,这种情况要求保证最长距离为k时,选出的子树中,至少有两个中心结点的儿子节点并且它们的最长距离为k。这个想了挺长时间没什么好办法,只好用dp搞一搞,dp2[i][0],dp[i][1],dp[i][2]分别表示以前i个儿子结点构成的子树中,长度为k的子树有0个,1个,大于等于2个,那么可以写成状态转移方程:
dp2[j][0]=dp2[j-1][0]*(1+dp[v][i-1]);
dp2[j][1]=dp2[j-1][1]*(1+dp[v][i-1])+dp2[j-1][0]*(dp[v][i]-dp[v][i-1]);
dp2[j][2]=dp2[j-1][2]*(1+dp[v][i-1])+(dp2[j-1][1]+dp2[j-1][2])*(dp[v][i]-dp[v][i-1]);
最后加上答案就行了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1000+10;
const int mod=10086;
struct Edge
{
int v,next;
Edge(){}
Edge(int v,int next):v(v),next(next){}
}edges[maxn<<1];
int head[maxn],dp[maxn][maxn],son[maxn],dp2[maxn][3],nEdge;
int res[2],d[maxn],S[maxn],p[maxn],minlen;
void AddEdges(int u,int v)
{
edges[++nEdge]=Edge(v,head[u]);
head[u]=nEdge;
edges[++nEdge]=Edge(u,head[v]);
head[v]=nEdge;
}
void dfs(int u,int fa)
{
dp[u][0]=dp[u][1]=0;
son[u]=0;
for(int k=head[u];k!=-1;k=edges[k].next)
{
int v=edges[k].v;
if(v==fa) continue;
dfs(v,u);
if(dp[v][0]+1>dp[u][0])
{
dp[u][1]=dp[u][0];
dp[u][0]=dp[v][0]+1;
son[u]=v;
}
else if(dp[v][0]+1>dp[u][1])
dp[u][1]=dp[v][0]+1;
}
}
void dfs2(int u,int fa,int maxlen)
{
int tmp=max(maxlen,dp[u][0]);
if(tmp<minlen)
{
minlen=tmp;
res[0]=u;
res[1]=-1;
}
else if(tmp==minlen)
res[1]=u;
for(int k=head[u];k!=-1;k=edges[k].next)
{
int v=edges[k].v;
if(v==fa) continue;
tmp=(son[u]==v)?dp[u][1]+1:dp[u][0]+1;
dfs2(v,u,max(maxlen+1,tmp));
}
}
void init()
{
memset(head,0xff,sizeof(head));
memset(son,0,sizeof(son));
memset(d,0,sizeof(d));
nEdge=res[0]=res[1]=-1;
minlen=inf;
}
void DFS(int u,int fa)
{
for(int i=0;i<maxn;++i) dp[u][i]=1;
for(int k=head[u];k!=-1;k=edges[k].next)
{
int v=edges[k].v;
if(v==fa) continue;
DFS(v,u);
for(int i=1;i<maxn;++i)
dp[u][i]=(dp[u][i]+dp[u][i]*dp[v][i-1])%mod;
}
}
int solve(int n)
{
dfs(1,-1);
dfs2(1,-1,0);
int type=(res[1]!=-1);
DFS(res[0],res[1]);
if(type) DFS(res[1],res[0]);
int ans=1,size;
if(type==0)
{
size=0;
for(int k=head[res[0]];k!=-1;k=edges[k].next)
S[++size]=edges[k].v;
if(size>1) ans=(ans+p[size]-size-1)%mod;
for(int i=1;i<maxn;++i)
{
dp2[0][0]=1;dp2[0][1]=dp2[0][2]=0;
for(int j=1;j<=size;++j)
{
dp2[j][0]=dp2[j-1][0]*(1+dp[S[j]][i-1])%mod;
dp2[j][1]=dp2[j-1][1]*(1+dp[S[j]][i-1])%mod+dp2[j-1][0]*(dp[S[j]][i]-dp[S[j]][i-1])%mod;
dp2[j][2]=dp2[j-1][2]*(1+dp[S[j]][i-1])%mod+(dp2[j-1][1]+dp2[j-1][2])*(dp[S[j]][i]-dp[S[j]][i-1])%mod;
dp2[j][1]%=mod;dp2[j][2]%=mod;
}
ans=(ans+dp2[size][2])%mod;
}
}
else
{
int tmp1,tmp2;
for(int i=1;i<maxn;++i)
{
tmp1=dp[res[0]][i]-dp[res[0]][i-1];
tmp2=dp[res[1]][i]-dp[res[1]][i-1];
ans=(ans+tmp1*tmp2)%mod;
}
}
return (ans%mod+mod)%mod;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
p[0]=1;
for(int i=1;i<maxn;++i) p[i]=(p[i-1]<<1)%mod;
int n,t,tcase=0;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();
int u,v;
for(int i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
AddEdges(u,v);
}
printf("Case %d: %d\n",++tcase,solve(n));
}
return 0;
}