1. 程式人生 > >[PKUWC2018]隨機遊走(MinMax容斥+樹形DP)

[PKUWC2018]隨機遊走(MinMax容斥+樹形DP)

print scanf 直接 style 困難 printf b+ stdout -s

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\n",ans); 40 } 41 return 0; 42 }

[PKUWC2018]隨機遊走(MinMax容斥+樹形DP)