[PKUWC2018] 随机游走
\(\text{Problem}:\)[PKUWC2018]随机游走
\(\text{Solution}:\)
设 \(t_{i}\) 表示点 \(i\) 第一次被经过的时间,则要求的显然是 \(E(\max\limits_{i\in S}t_{i})\)。\(\max\) 难求,可以考虑 \(\min-\max\) 容斥,由期望的线性性,得到:
现在要求的是点集 \(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}\)。现在将前面的式子改写:
如果 \(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\),则要求的是:
这个直接上子集卷积,在 \(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;
}