简单题 解题报告

简单题

给一颗\(n(\le 80)\)节点的树,开始所有节点都是白色,每个时间随机染黑一条链,求把整棵树染黑的期望时间,对\(998244353\)取模


考虑\(\min-\max\)容斥

某集合\(S\)最后一个点出现的期望时间为\(\max S\),第一个点出现的期望时间是\(\min S\),则有
\[ \max(S)=\sum_{\varnothing\not=T\subseteq S}(-1)^{T-1}\min (T) \]
考虑求出\(\min T\)

一个显然的暴力是枚举所有\(T\),然后枚举所有染色方案,求出不经过这\(T\)的染色方案的概率\(p\)

那么\(\min (T)=\sum\limits_{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\n",ans);
    return 0;
}

2019.3.28

猜你喜欢

转载自www.cnblogs.com/butterflydew/p/10617101.html