zoukankan      html  css  js  c++  java
  • 【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] imes (-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
    ",ans[hh]);
    70     }
    71 }
  • 相关阅读:
    20200924-5 四则运算试题生成,结对
    20200924-4 代码规范,结对要求
    20200929-git地址
    20200917-1 每周例行报告
    20200917-3白名单
    20200917-2 词频统计
    20200910-1 每周例行报告
    20200910-2 博客作业
    20200924-3 单元测试,结对
    20200924-5 四则运算试题生成,结对
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9363974.html
Copyright © 2011-2022 走看看