[PKUWC2018]随机游走

Posted ytxytx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[PKUWC2018]随机游走相关的知识,希望对你有一定的参考价值。

题目大意

给你一颗树和根,每次询问从根出发,随机走到有连边的结点,经过集合S中所有结点的步数期望

(1 leq n leq 18,1 leq Q leq 5000)

解题思路

首先我们要求出所有集合(S)经过至少一个(S)中的点的步数期望(为最值反演铺垫)

(dp_{S,i})表示以i为起点,要经过集合S中至少一个点的步数期望

那么(dp_{S,i}=frac{1}{dig_i}(dp_{S,fa_i}+1+sum_{vin son}{dp_{S,v}+1}))(dig)表示(i)的度数

根据套路,我们假设(dp_{S,i}=A_idp_{S,fa_i}+B_i)

[ egin{align} dp_{S,i} & =frac{1}{dig_i}(dp_{S,fa_i}+1+sum_{vin son}{dp_{S,v}+1}) & =frac{1}{dig_i}(dp_{S,fa_i}+1+sum_{vin son}{A_vdp_{S,i}+B_v+1}) & =frac{1}{dig_i}(dp_{S,fa_i}+dp_{S,i}sum_{vin son}{A_v}+sum_{vin son}{B_v})+1 & =frac{1}{dig_i}(dp_{S,fa_i}+dp_{S,i}sigA+sigB)+1 dig_idp_{S,i} & =dp_{S,fa_i}+dp_{S,i}sigA+sigB+1 (dig_i-sigA)dp_{S,i} & =dp_{S,fa_i}+sigB+1 dp_{S,i} & =frac{1}{dig_i-sigA}dp_{S,fa_i}+frac{sigB+1}{dig_i-sigA} end{align} ]

于是我们得到了

[ A_i=frac{1}{dig_i-sigA} ]
[ B_i=frac{sigB+1}{dig_i-sigA} ]

显然如果(iin S)那么(A_i=B_i=0)

然后A,B是可以在树上dp的(因为式子只和它的孩子有关)

那么我们要求的

[ egin{align} dp_{S,root} & = A_{root}dp_{S,fa_{root}}+B_{root} & = B_{root} end{align} ]

于是每次询问集合S,只需要进行最值反演,(max(S)=sum_{S‘subseteq S}{dp_{S‘,root}cdot (-1)^{|S‘|+1}})

(max(S))即为每次询问的答案

#include<iostream>
#include<cstdio>

const int P=998244353;

struct edge{
    int to,next;
}E[60];
int H[30],tot;
void add_edge(int a,int b){
    E[++tot]=(edge){b,H[a]};H[a]=tot;
    E[++tot]=(edge){a,H[b]};H[b]=tot;
}

int n,Q,St,x,y,k,ch[30];
long long ans;
long long A[30],B[30],dp[3000000],dig[30];

long long inv(long long k){return (k==1)?(1):((P-P/k)*inv(P%k)%P);}

void dfs(int S,int now,int fa){
    if ((1<<(now-1))&S){
        A[now]=B[now]=0;
        return;
    }
    long long sigA=0,sigB=0;
    for (int i=H[now];i;i=E[i].next){
        if (E[i].to==fa) continue;
        dfs(S,E[i].to,now);
        sigA=(sigA+A[E[i].to])%P;
        sigB=(sigB+B[E[i].to])%P;
    }
    long long Inv=(dig[now]==sigA)?(0):(inv(dig[now]-sigA));
    A[now]=Inv;
    B[now]=(sigB+dig[now])%P*Inv%P;
}

void Min_Max(int now,int S,int f){
    if (now>k){ans=(ans+f*dp[S]%P+P)%P;return;}
    Min_Max(now+1,S,f);
    Min_Max(now+1,S|(1<<(ch[now]-1)),-f);
}

int main(){
    scanf("%d%d%d",&n,&Q,&St);
    for (int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        dig[x]++;dig[y]++;
        add_edge(x,y);
    }
    for (int i=0;i<(1<<n);i++){
        dfs(i,St,0);
        dp[i]=B[St];
    }
    for (int i=1;i<=Q;i++){
        scanf("%d",&k);
        for (int j=1;j<=k;j++) scanf("%d",&ch[j]);
        ans=0;
        Min_Max(1,0,-1);
        printf("%lld
",ans);
    }
}

以上是关于[PKUWC2018]随机游走的主要内容,如果未能解决你的问题,请参考以下文章

「PKUWC2018」随机游走

[PKUWC2018]随机游走

题解-PKUWC2018 随机游走

「PKUWC2018」随机游走

[PKUWC2018]随机游走(MinMax容斥+树形DP)

P5643 [PKUWC2018]随机游走 min-max容斥+FWT