【LOJ 2542】【PKUWC2018】 随机游走(最值反演 + 树上期望dp)

哇我太菜啦555555

不妨钦定我们需要访问的点集为$S$,在$S$已知的情况下,我们令$f(x) $表示从$x$走到点集$S$中任意一点的期望步数。

若$x∈S$,则显然$f(x)=0$,否则$f[x]=\frac{1}{d[x]}\sum f[ch[x]]+1$。其中$d[x]$表示与$x$相连的节点个数,$ch[x]$为与$x$相连的节点。

然后就列出了$n$条式子,显然是一个$n$元一次方程,可以考虑用高斯消元去求解,这样时间复杂度是$O(n^32^{n})$,只能拿$60$分(然而我考场上是零分啊呜呜呜)

我们考虑用些快速点的方法,考虑将$f[x]$化为$A_xf[fa[x]]+B_x$。其中$fa[x]$表示$x$的父亲。

$f[x]=A_x[fa[x]]+B_x=\frac{1}{d[x]}\sum f[ch[x]]$

$f[x]=\frac{1}{d[x]}f[fa[x]]+\frac{1}{d[x]}(A_{ch[x]}f[x]+B_{ch[x]})+1$。

经过化简后,得

$f[x]= \dfrac{f[fa[x]]+\sum B_{ch[x]}+1}{d[u]-\sum A_{ch[x]}}$

我们令$g[S]$表示从给定起点$X$出发,走到集合$S$中任意一个点的期望步数。

那么显然,$g[S]=f[X]$。求出所有状态的期望的时间复杂度显然为$O(n 2^n)$。

我们令$G[S]$表示从给定起点$X$出发,将集合$S$中每个点至少走一次的期望步数。

根据$min-max$容斥的相关内容,有

$G[S]=\sum_{i∈S}g[i]\times (-1)^{|i|+1}$

然后我们可以花$O(3^n)$枚举子集,预处理出所有答案。

查询的时候$O(1)$查询即可。

完结撒花

 1 #include<bits/stdc++.h>
 2 #define M 18
 3 #define MOD 998244353
 4 #define L long long
 5 using namespace std;
 6 
 7 L pow_mod(L x,L k){
 8     L ans=1;
 9     while(k){
10         if(k&1) ans=ans*x%MOD; 
11         x=x*x%MOD; k>>=1;
12     }
13     return ans;
14 }
15 
16 L d[M]={0},invd[M]={0};    
17 struct edge{int u,next;}e[M<<1]={0}; int head[M]={0},use=0;
18 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
19 
20 L f[1<<M]={0},ans[1<<M]={0},zf[1<<M]={0},a[M]={0},b[M]={0}; int ok[1<<M]={0};
21 
22 int n,q,rt;
23 void dfs(int x,int fa,int S){
24     if((1<<x)&S) return;
25     for(int i=head[x];i;i=e[i].next)
26     if(e[i].u!=fa){
27         dfs(e[i].u,x,S);
28         b[x]+=b[e[i].u];
29         a[x]+=a[e[i].u];
30     }
31     b[x]%=MOD; a[x]%=MOD;
32     L inv=pow_mod((d[x]-a[x]+MOD)%MOD,MOD-2);
33     a[x]=inv; 
34     b[x]=(b[x]*inv+inv*d[x])%MOD;
35 }
36 
37 void solve(int x){
38     ok[x]=1;
39     for(int i=x;i;i=x&(i-1))
40     ans[x]+=zf[i]*f[i];
41     ans[x]=(ans[x]%MOD+MOD)%MOD;
42 }
43 
44 int main(){
45     //freopen("a.out","w",stdout);
46     scanf("%d%d%d",&n,&q,&rt); rt--;
47     for(int i=1;i<n;i++){
48         int x,y; scanf("%d%d",&x,&y);
49         x--; y--; add(x,y); add(y,x);
50         d[x]++; d[y]++;
51     }
52     for(int i=0;i<n;i++) invd[i]=pow_mod(d[i],MOD-2);
53     int hh=1<<n;
54     for(int i=1;i<hh;i++){
55         memset(a,0,sizeof(a)); 
56         memset(b,0,sizeof(b));
57         dfs(rt,-1,i);
58         f[i]=b[rt]; zf[i]=-1;
59         for(int j=0;j<n;j++)
60         if((1<<j)&i) zf[i]=-zf[i];
61     }
62     while(q--){
63         int k,hh=0; scanf("%d",&k);
64         while(k--){
65             int x; scanf("%d",&x); 
66             hh+=1<<(x-1);
67         }
68         if(!ok[hh]) solve(hh);
69         printf("%lld\n",ans[hh]);
70     }
71 }

猜你喜欢

转载自www.cnblogs.com/xiefengze1/p/9363974.html
今日推荐