简单题
给一颗(n(le 80))节点的树,开始所有节点都是白色,每个时间随机染黑一条链,求把整棵树染黑的期望时间,对(998244353)取模
考虑(min-max)容斥
某集合(S)最后一个点出现的期望时间为(max S),第一个点出现的期望时间是(min S),则有
[max(S)=sum_{varnothing
ot=Tsubseteq S}(-1)^{T-1}min (T)
]
考虑求出(min T)
一个显然的暴力是枚举所有(T),然后枚举所有染色方案,求出不经过这(T)的染色方案的概率(p)
那么(min (T)=sumlimits_{i= 0}^{infty}p^i=frac{1}{1-p})
于是可以(dp)染色方案数目,求出概率
令(dp_{i,j,k})表示(i)子树有(j)个点到(i)的路径上没有白点且共有(k)条路径没有白点的方案数,并把容斥系数也带上
转移的时候枚举每一维,然后拼一拼,第二维压进去是给第三维转移用的,至于复杂度,不是很清楚呢...
Code:
#include <cstdio>
#include <cctype>
#include <cstring>
template <class T>
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int mod=998244353;
const int N=85;
inline void add(int &a,int b){a=a+b>=mod?a+b-mod:a+b;}
#define mul(a,b) (1ll*(a)*(b)%mod)
int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
int head[N],Next[N<<1],to[N<<1],cnt;
void addedge(int u,int v)
{
to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int dp[N][N][N*N/2],f[N][N*N/2],siz[N],n,ans;
void dfs(int now,int fa)
{
dp[now][0][0]=mod-1;
dp[now][1][1]=1;
siz[now]=1;
for(int v,p=head[now];p;p=Next[p])
if((v=to[p])!=fa)
{
dfs(v,now);
for(int i=0;i<=siz[now];i++)
for(int k=i*(i+1)/2;k<=siz[now]*(siz[now]+1)/2;k++)
if(dp[now][i][k])
for(int j=0;j<=siz[v];j++)
for(int l=j*(j+1)/2;l<=siz[v]*(siz[v]+1)/2;l++)
add(f[i?i+j:0][k+l+i*j],mul(dp[now][i][k],dp[v][j][l]));
siz[now]+=siz[v];
for(int i=0;i<=siz[now];i++)
for(int k=0;k<=siz[now]*(siz[now]+1)/2;k++)
dp[now][i][k]=f[i][k],f[i][k]=0;
}
}
int main()
{
freopen("jiandanti.in","r",stdin);
freopen("jiandanti.out","w",stdout);
read(n);
for(int u,v,i=1;i<n;i++) read(u),read(v),addedge(u,v),addedge(v,u);
dfs(1,0);
int m=n*(n+1)/2;
for(int i=0;i<=m;i++)
{
int t=0;
for(int j=0;j<=n;j++) add(t,dp[1][j][i]);
add(ans,mul(mod-1,mul(t,mul(m,qp(m-i,mod-2)))));
}
printf("%d
",ans);
return 0;
}
2019.3.28