Marser
2019-11-12 08:04:48
给定一棵
有
一般的随机游走问题,由于后效性,必须考虑列方程组,通过高斯消元求解。但是,这题是树上的随机游走问题,只能从父亲与儿子转移,可以考虑直接dp。
由于本题要求点集
设
若
按照套路,将转移方程写成有关于父亲的函数,即
发现
所以点集
预处理所有
但是这样做很不优美,我们考虑一些更加优雅的做法。
考虑集合或卷积的形式:
我们计
所以,经过FWT集合或卷积变换后,新多项式是原多项式的子集和。
可以运用单次FWT预处理所有子集和,复杂度
#include<bits/stdc++.h>
#define reg register
typedef long long ll;
using namespace std;
const int MN=19;
const int mod=998244353;
int to[MN<<1],nxt[MN<<1],h[MN],cnt;
inline void ins(int s,int t){
to[++cnt]=t;nxt[cnt]=h[s];h[s]=cnt;
to[++cnt]=s;nxt[cnt]=h[t];h[t]=cnt;
}
inline ll qpow(ll a,ll b){
reg ll res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;b>>=1;
}
return res;
}
int deg[MN],A[MN],B[MN];
void dfs(int st,int fa,int S){
reg int totA=0,totB=0,inv=0;
if(S&(1<<st-1))return;
for(reg int i=h[st];i;i=nxt[i])
if(to[i]!=fa){
dfs(to[i],st,S);
totA=(totA+A[to[i]])%mod;
totB=(totB+B[to[i]])%mod;
}
inv=qpow((deg[st]-totA+mod)%mod,mod-2);
A[st]=inv;B[st]=1ll*inv*(totB+deg[st])%mod;
}
int n,q,root,U,F[1<<18|5],Ans;
int main(){
scanf("%d%d%d",&n,&q,&root);
for(reg int i=1,s,t;i<n;i++){
scanf("%d%d",&s,&t),ins(s,t);
deg[s]++;deg[t]++;
}
U=1<<n;
for(reg int S=1;S<U;S++){
for(reg int i=1;i<=n;i++)A[i]=B[i]=0;dfs(root,0,S);
F[S]=(((__builtin_popcount(S)&1)?1:-1)*B[root]+mod)%mod;
}
for(reg int i=1;i<U;i<<=1)
for(reg int len=i<<1,j=0;j<U;j+=len)
for(reg int k=0;k<i;k++)
F[i+j+k]=(F[i+j+k]+F[j+k])%mod;
while(q--){
static int k,S;scanf("%d",&k);S=0;
for(reg int i=1,x;i<=k;i++)
scanf("%d",&x),S|=(1<<x-1);
printf("%d\n",(F[S]+mod)%mod);
}
return 0;
}