题解:CF1517F Reunion
更好的阅读体验
这也太难了,根本不会啊。
首先把贡献为
我们假设点集
我们觉得
接下来假设有空的是白点,没空的是黑点。那么存在一个点半径为
我们假设
假设一个点已经满足了子树内的限制,也就是这个点的子树内,离它最近的黑点到它的距离已经超过
所以我们假设
首先有初始值
那么考虑转移,下文中
- 合并
f_{u, i}, f_{v, j} :这是简单的,只要分别枚举两个子树内最浅的黑点到u 的距离i, j ,合并后的距离是\min(i, j+1) 。f_{u, \min(i, j+1)} \leftarrow f_{u, i} \cdot f_{v, j} - 合并
g_{u, i}, g_{v, j} :同理,枚举两个子树内最深的好点的深度。
- 合并
f_{u, i}, g_{v, j} 。如果j+1+i \le r ,说明g 子树内的好点全部被u 子树内的黑点击落了,所以转移到f_{u, i} ,否则v 子树的好点不变,转移到g_{u, j+1} 。
- 合并
g_{u, i}, f_{v, j} 。同 3,如果j+1+i \le r ,说明u 子树内的好点全部被v 子树内的黑点击落了,所以转移到f_{v, j+1} ,否则转移到g_{u, i} 。
我们首先枚举
最后记得除以
那么这道题就做完了,复杂度
#include<bits/stdc++.h>
#define endl '\n'
#define N 306
#define MOD 998244353
using namespace std;
inline void add(int &x,int y) {x+=y,x-=x>=MOD?MOD:0;}
int n,ans,sz[N],f[N][N],g[N][N],tf[N],tg[N];
vector<int> G[N];
void dfs(int u,int fa,int r)
{
f[u][0]=g[u][0]=sz[u]=1;
for(int v:G[u])if(v!=fa)
{
dfs(v,u,r);
for(int i=0;i<=sz[u];i++)
for(int j=0;j<=sz[v];j++)
{
add(tf[min(i,j+1)],1ll*f[u][i]*f[v][j]%MOD);
add(tg[max(i,j+1)],1ll*g[u][i]*g[v][j]%MOD);
if(i+j+1>r)
{
add(tg[i],1ll*g[u][i]*f[v][j]%MOD);
add(tg[j+1],1ll*f[u][i]*g[v][j]%MOD);
} else {
add(tf[i],1ll*f[u][i]*g[v][j]%MOD);
add(tf[j+1],1ll*g[u][i]*f[v][j]%MOD);
}
}
for(int i=0;i<=sz[u]+sz[v];i++)
f[u][i]=tf[i],tf[i]=0,g[u][i]=tg[i],tg[i]=0;
sz[u]+=sz[v];
}
}
int solve(int r)
{
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
dfs(1,0,r); int ret=0;
for(int i=0;i<n;i++)add(ret,g[1][i]);
return ret;
}
main()
{
scanf("%d",&n);
for(int i=1,u,v;i<n;i++)
scanf("%d%d",&u,&v),G[u].push_back(v),G[v].push_back(u);
for(int i=1;i<n;i++)add(ans,solve(i));
for(int i=1;i<=n;i++)ans=499122177ll*ans%MOD;
printf("%d\n",ans);
return 0;
}