[LOJ2542][PKUWC2018]随机游走(MinMax容斥+树上高斯消元)

MinMax容斥将问题转化为求x到S中任意点的最小时间。

树形DP,直接求概率比较困难,考虑只求系数。最后由于x节点作为树根无父亲,所以求出的第二个系数就是答案。

https://blog.csdn.net/dearbaba_8520/article/details/80556499

$O((n+q)2^n)$

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 4 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 5 using namespace std;
 6 
 7 const int N=20,mod=998244353;
 8 int n,Q,rt,u,v,cnt,A[N],B[N],d[N],invd[N],h[N],to[N<<1],nxt[N<<1],Min[1<<N],bit[1<<N];
 9 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
10 
11 int ksm(int a,int b){
12     int res=1;
13     for (; b; a=1ll*a*a%mod,b>>=1)
14         if (b & 1) res=1ll*res*a%mod;
15     return res;
16 }
17 
18 void DP(int x,int fa,int S){
19     if ((1<<(x-1))&S){ A[x]=B[x]=0; return; }
20     int ta=0,tb=0;
21     For(i,x) if ((k=to[i])!=fa)
22         DP(k,x,S),ta=(ta+A[k])%mod,tb=(tb+B[k])%mod;
23     int c=ksm((1-1ll*ta*invd[x]%mod+mod)%mod,mod-2);
24     A[x]=1ll*invd[x]*c%mod; B[x]=(1+1ll*tb*invd[x])%mod*c%mod;
25 }
26 
27 int main(){
28     freopen("walk.in","r",stdin);
29     freopen("walk.out","w",stdout);
30     scanf("%d%d%d",&n,&Q,&rt);
31     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u),d[u]++,d[v]++;
32     rep(i,1,n) invd[i]=ksm(d[i],mod-2);
33     int ed=(1<<n)-1;
34     rep(i,0,ed) DP(rt,0,i),Min[i]=B[rt],bit[i]=bit[i>>1]+(i&1);
35     while (Q--){
36         int S=0,ans=0,x,k; scanf("%d",&k);
37         while (k--) scanf("%d",&x),S|=1<<(x-1);
38         for (int i=S; i; i=(i-1)&S) ans=(ans+1ll*(bit[i]&1 ? 1 : -1)*Min[i]+mod)%mod;
39         printf("%d
",ans);
40     }
41     return 0;
42 }
原文地址:https://www.cnblogs.com/HocRiser/p/10197789.html