LG P5643 [PKUWC2018]随机游走

Description

给定一棵 $n$个结点的树,你从点 $x$出发,每次等概率随机选择一条与所在点相邻的边走过去。

有 $q$次询问,每次询问给定一个集合$S$,求如果从 $x$出发一直随机游走,直到点集$S$ 中所有点都至少经过一次的话,期望游走几步。

特别地,点 $x$(即起点)视为一开始就被经过了一次。

答案对$998244353$ 取模。

Solution

把遍历整个点集的期望时间视为遍历点集中每个点的时间的最大值,就可以使用MinMax容斥

$$Max(S)=\sum_{T \subseteq S}(-1)^{|T|-1}Min(T)$$

令$f(i,S)$表示从$i$到达点集$S$的点的时间最小值,即访问任意一个点的期望时间,所以$Min(S)=f(i,S)$

其表达式为

$$f(i,S)=
\begin{cases}
0& \text{$i \in S$}\\
\frac{f(fa_i,S)}{deg_i} + \frac{\sum_{j \in son_i}f(j,S)}{deg_i}+1& \text{$i \notin S$}\\
\end{cases}$$

设$f(i,S)=A_i \times f(fa_i,S)+B_i$,代入化简得

$$A_i=\frac{1}{deg_i - \sum_{j \in son_i}A_j},B_i=\frac{\sum_{j\in son_i} B_j + deg_i}{deg_i - \sum_{j \in son_i}A_j}$$

预处理子集答案,从下向上递推

 

#include<iostream>
#include<cstdio>
using namespace std;
long long n,q,root,tot,head[20],A[20],B[20],deg[20],bits[1100000],ans[1100000];
const long long mod=998244353;
struct Edge
{
    long long to,nxt;
} edge[40];
inline long long read()
{
    long long f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
        {
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        w=(w<<1)+(w<<3)+ch-'0';
        ch=getchar();
    }
    return f*w;
}
long long ksm(long long a,long long p)
{
    long long ret=1;
    while(p)
    {
        if(p&1)
        {
            (ret*=a)%=mod;
        }
        (a*=a)%=mod;
        p>>=1;
    }
    return ret;
}
void dfs(long long k,long long fa,long long sta)
{
    if((1<<(k-1))&sta)
    {
        A[k]=B[k]=0;
        return;
    }
    A[k]=B[k]=deg[k];
    for(long long i=head[k]; i; i=edge[i].nxt)
    {
        long long v=edge[i].to;
        if(v!=fa)
        {
            dfs(v,k,sta);
            ((A[k]-=A[v])+=mod)%=mod;
            (B[k]+=B[v])%=mod;
        }
    }
    A[k]=ksm(A[k],mod-2);
    (B[k]*=A[k])%=mod;
}
int main()
{
    n=read();
    q=read();
    root=read();
    for(long long i=1; i<n; i++)
    {
        long long u=read(),v=read();
        edge[++tot]=(Edge){v,head[u]};
        head[u]=tot;
        edge[++tot]=(Edge){u,head[v]};
        head[v]=tot;
        ++deg[u];
        ++deg[v];
    }
    for(long long i=1;i<(1<<n);i++)
    {
        bits[i]+=bits[i>>1]+(i&1);
    }
    for(long long i=1; i<(1<<n); i++)
    {
        dfs(root,0,i);
        if(bits[i]&1)
        {
            ans[i]=B[root];
        }
        else
        {
            ans[i]=mod-B[root];
        }
    }
    for(long long i=0;i<n;i++)
    {
        for(long long j=0;j<(1<<n);j++)
        {
            if((1<<i)&j)
            {
                (ans[j]+=ans[j^(1<<i)])%=mod;
            }
        }
    }
    for(long long i=1;i<=q;i++)
    {
        long long k=read(),nowsta=0;
        for(long long j=1;j<=k;j++)
        {
            long long num=read();
            nowsta|=(1<<(num-1));
        }
        printf("%lld\n",ans[nowsta]);
    }
    return 0;
}
随机游走

 

posted @ 2020-08-06 11:34  QDK_Storm  阅读(146)  评论(0编辑  收藏  举报