[PKUWC2018] 随机游走

\(\text{Problem}:\)[PKUWC2018]随机游走

\(\text{Solution}:\)

\(t_{i}\) 表示点 \(i\) 第一次被经过的时间,则要求的显然是 \(E(\max\limits_{i\in S}t_{i})\)\(\max\) 难求,可以考虑 \(\min-\max\) 容斥,由期望的线性性,得到:

\[E\left(\max\limits_{i\in S} t_{i}\right)=E\left(\sum\limits_{T\subseteq S}(-1)^{\lvert T \rvert-1}\min\limits_{i\in T}t_{i}\right)=\sum\limits_{T\subseteq S}(-1)^{\lvert T \rvert-1}E\left(\min\limits_{i\in T}t_{i}\right) \]

现在要求的是点集 \(T\) 中,至少有一个点被经过的期望时间。设 \(f_{i}\) 表示从 \(i\) 开始随机游走,第一次经过 \(T\) 中某个结点的期望时间,得到(钦定给出的树以 \(1\) 为根):

  • \(x\in T\)\(f_{x}=0\)
  • \(x\notin T\)\(f_{x}=1+\cfrac{1}{deg_{x}}\cdot (f_{y}+\sum\limits_{z\in son_{x}}f_{z})\)。其中,\(y\)\(x\) 的父亲,\(son_{x}\)\(x\) 的孩子集合。

对于每个 \(x\) 都有一个方程,用高斯消元可以在 \(O(n^{3})\) 的时间复杂度内对每个 \(T\) 求出答案,但无法通过本题。考虑优化这一过程。

发现对于叶子结点 \(x\),有 \(f_{x}=f_{y}+1\),那么在 \(f_{y}\) 的孩子集合中,可以将 \(f_{x}\) 改为 \(f_{y}+1\)。这提示我们可以对任意 \(x\) 列出只与父亲有关的方程,即 \(f_{x}=A_{x}f_{y}+B_{x}\)。现在将前面的式子改写:

\[f_{x}=1+\cfrac{f_{y}}{deg_{x}}+\cfrac{1}{deg_{x}}\sum\limits_{z\in son_{x}}(A_{z}f_{x}+B_{z})=\cfrac{f_{y}+deg_{x}+\sum B_{z}}{deg_{x}-\sum A_{z}} \]

如果 \(x\in T\)\(A_{x}=B_{x}=0\);否则,对于叶子结点,\(A_{x}=B_{x}=1\),对于非叶子结点,\(A_{x}=\cfrac{1}{deg_{x}-\sum A_{z}}\)\(B_{x}=\cfrac{deg_{x}+\sum B_{z}}{deg_{x}-\sum A_{z}}\)。而 \(f_{1}=B_{1}\),于是可以推出其他 \(f_{x}\) 的值。故对于所有 \(T\),求出 \(E\left(\min\limits_{i\in T}t_{i}\right)\) 的总时间复杂度为 \(O(n\cdot 2^{n})\)

\(F(T)=E\left(\min\limits_{i\in T}t_{i}\right)\times (-1)^{\lvert T \rvert-1}\)\(G(T)=1\),则要求的是:

\[E\left(\max\limits_{i\in S} t_{i}\right)=\sum\limits_{i\&j=0\\i|j=S} F(i)G(j) \]

这个直接上子集卷积,在 \(O(n^{2}\cdot 2^{n})\) 的时间复杂度内可以解决。当然,由于 \(G(i)=1\),也可以优化到 \(O(n\cdot 2^{n})\)

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=19, Mod=998244353;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,Q,X,deg[N],dp[N],A[N],B[N];
int F[N][(1<<(N-1))+5],G[N][(1<<(N-1))+5],H[N][(1<<(N-1))+5],num[(1<<(N-1))+5];
int head[N],maxE; struct Edge { int nxt,to; }e[N<<1];
inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=1ll*x*x%Mod) if(p&1) res=1ll*res*x%Mod; return res; }
void DFS1(int x,int fa,int T)
{
	int sz=0;
	A[x]=1, B[x]=deg[x];
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		DFS1(v,x,T);
		(B[x]+=B[v])%=Mod;
		(sz+=A[v])%=Mod;
	}
	if((T>>(x-1))&1) A[x]=B[x]=0;
	else
	{
		int fm=ksc((deg[x]-sz+Mod)%Mod,Mod-2);
		A[x]=1ll*A[x]*fm%Mod;
		B[x]=1ll*B[x]*fm%Mod;
	}
}
void DFS2(int x,int fa,int T)
{
	if((T>>(x-1))&1) dp[x]=0;
	else dp[x]=(1ll*A[x]*dp[fa]%Mod+B[x])%Mod;
	for(ri int i=head[x];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(v==fa) continue;
		DFS2(v,x,T);
	}
}
inline void OR(int *s,int type)
{
	for(ri int i=2;i<=(1<<n);i<<=1)
	for(ri int j=0,mid=(i>>1);j<(1<<n);j+=i)
	for(ri int k=0;k<mid;k++)
	{
		if(~type) (s[j+mid+k]+=s[j+k])%=Mod;
		else (s[j+mid+k]+=Mod-s[j+k])%=Mod;
	}
}
signed main()
{
	n=read(), Q=read(), X=read();
	for(ri int i=1;i<n;i++)
	{
		int u,v;
		u=read(), v=read();
		Add(u,v), Add(v,u);
		deg[u]++, deg[v]++;
	}
	G[0][0]=1;
	for(ri int i=1;i<(1<<n);i++)
	{
		int cnt=0;
		for(ri int j=1;j<=n;j++) dp[j]=0, cnt+=((i>>(j-1))&1);
		num[i]=cnt;
		G[cnt][i]=1;
		if((i>>(X-1))&1) continue;
		DFS1(1,0,i), DFS2(1,0,i);
		if((cnt-1)&1) F[cnt][i]=Mod-dp[X];
		else F[cnt][i]=dp[X];
	}
	for(ri int i=0;i<=n;i++) OR(F[i],1), OR(G[i],1);
	for(ri int i=0;i<=n;i++)
	for(ri int j=0;j<=i;j++)
	for(ri int k=0;k<(1<<n);k++)
	{
		H[i][k]=(H[i][k]+1ll*F[j][k]*G[i-j][k]%Mod)%Mod;
		if(H[i][k]<0) H[i][k]+=Mod;
	}
	for(ri int i=0;i<=n;i++) OR(H[i],-1);
	for(ri int i=1;i<=Q;i++)
	{
		int ki=read();
		int S=0;
		for(ri int j=1;j<=ki;j++)
		{
			int x=read();
			S|=(1<<(x-1));
		}
		printf("%d\n",H[num[S]][S]);
	}
	return 0;
}
posted @ 2021-04-15 21:27  zkdxl  阅读(57)  评论(0编辑  收藏  举报