题解:AT_mujin_pc_2017_d Oriented Tree
idea from ryz
题目大意很简单,就是说给一棵树的边定向,然后令树上路径
考虑路径,既然是路径,我们肯定想到不妨直接来个最长的路径,那么这个最长的路径的长度权值最大的可能性是最大的,所以不妨设这棵树的直径为
所以现在我们知道了答案,就考虑计数。计数不如还选择直径的中点作为根,记作
那么就可以树形dp了,令
/*胡金梁*/
#include<bits/stdc++.h>
using namespace std;
#define __MY_TEST__ 0
#define int long long
inline int read()
{
int f=1,re=0;
char ch=getchar();
while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar();}
while( isdigit(ch)) re=(re<<3)+(re<<1)+(ch^'0'),ch=getchar();
return re*f;
}
const int mod=1000000007;
vector<int>gra[1005];
int n,a,b,nxt[1005],dd,r1,r2,d,low[1005];
long long dp[1005][1005];
int dfs(int u,int fa)
{
int re=0;
for(auto v:gra[u])
{
if(v!=fa)
{
int tmp=dfs(v,u)+1;
if(tmp>re) re=tmp,nxt[u]=v;
}
}
return re;
}
void stag(int u,int fa,int tag)
{
if(tag==0)
{
low[u]=0;
}
else low[u]=2;
for(auto v:gra[u])
{
if(v!=fa)
{
stag(v,u,tag);
}
}
}
void solve(int u,int fa,int dep)
{
memset(dp[u],0,sizeof dp[u]);
for(int i=dep+low[u];i<=d-dep;i++)
{
dp[u][i]=1;
}
for(auto v:gra[u])
{
if(v!=fa)
{
solve(v,u,dep+1);
for(int i=dep+low[u];i<=d-dep;i++)
{
dp[u][i]*=(dp[v][i-1]+dp[v][i+1]);
dp[u][i]%=mod;
}
}
}
}
int DP(int r1,int r2,int tag)
{
stag(r1,r2,tag);
stag(r2,r1,0);
solve(r1,0,0);
int ans=0;
for(int i=0;i<=d;i++)
{
ans+=dp[r1][i];
ans%=mod;
}
return ans;
}
signed main()
{
#if __MY_TEST__
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
n=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read();
gra[u].push_back(v);
gra[v].push_back(u);
}
dfs(1,0);
int nw=1,ans=0;
r1=r2=0;
while(nxt[nw]!=0) nw=nxt[nw];
memset(nxt,0,sizeof nxt);
dd=dfs(nw,0);
for(int i=1;i<=dd;i++)
{
nw=nxt[nw];
if(i*2==dd) r1=nw;
if(i*2+1==dd) r1=nw;
if(i*2-1==dd) r2=nw;
}
d=dd+(dd&1);
if((dd&1)==0)
{
ans=DP(r1,0,0);
}
else
{
ans=((DP(r1,r2,0)+DP(r2,r1,0)-DP(r1,r2,1)-DP(r2,r1,1))%mod+mod)%mod;
}
if(n==2) cout<<2<<endl;
else cout<<ans<<endl;
}