专栏文章

题解:P4321 随机漫游

P4321题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@minn38xt
此快照首次捕获于
2025/12/02 05:06
3 个月前
此快照最后确认于
2025/12/02 05:06
3 个月前
查看原文
随机游走板子?
qq 次询问,给出点 uu 和点集 SS,求从 uu 出发随机游走刚好走过 SS 的所有点的期望步数,也就是经过 SS 中的某个点所用步数的最大的期望值,记为 Eu(max(S))E_u(\max (S))
套路地考虑 min-max 容斥,
Eu(max(S))=TS(1)T+1Eu(min(T))\displaystyle E_u(\max(S))=\sum_{T\subseteq S} (-1)^{|T|+1} E_u(\min(T))
考虑对于固定的 TT,对于所有 uu 求出 Eu(min(T))E_u(\min(T))
fu=Eu(min(T))f_{u}=E_u(\min(T)),容易得出以下转移,
fu={0uT1+(u,v)E1dufvu∉Tf_{u}= \begin{cases} 0 & u\in T\\ 1+\displaystyle\sum_{(u,v)\in E} \frac{1}{d_u}f_v & u\not\in T \end{cases}
显然转移存在环,不过可以列出一个 nn 个方程的 nn 元线性方程组,那么可以用高斯消元法 O(n3)O(n^3) 求出所有 fuf_u,进而得到所有 Eu(min(T))E_u(\min(T)),这一部分时间复杂度 O(n32n)O(n^3 2^n)
然后就要求 Eu(max(S))E_u(\max(S)) 了,发现容斥系数只与 T|T| 有关,直接对于每个点 uu,让所有 Eu(min(T))E_u(\min(T)) 带着容斥系数做高维前缀和即可。一共做 nn 遍高维前缀和,复杂度 O(n2n)O(n2^n)
在代码里,高维前缀和用 FWT 实现。
CPP
#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()

#define N 21
#define S (1<<18)+91
#define int long long
#define pcnt __builtin_popcount

const int mod=998244353;
int n,m,q,tot,a[N][N],d[N],f[N][S];
vector<int>e[N];

inline int qpow(int a,int b=mod-2){
    int ans=1;

    while(b){
        if(b&1){
            ans=ans*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }

    return ans;
}

inline void fwt(int *f,int n){
    int len=2,nx=1;

    while(len<=n){
        int i=0;
        while(i<n){
            rep(j,0,nx-1){
                f[i+j+nx]=(f[i+j+nx]+f[i+j])%mod;
            }
            i+=len;
        }

        len<<=1;
        nx<<=1;
    }
}

inline void gauss(int n){
    rep(i,1,n){
        if(!a[i][i]){
            continue;
        }

        int iv=qpow(a[i][i])%mod;

        rep(j,1,n){
            if(i==j){
                continue;
            }

            int c=a[j][i]*iv%mod;

            if(!c){
                continue;
            }

            rep(k,i,n+1){
                a[j][k]=(a[j][k]-c*a[i][k]%mod+mod)%mod;
            }
        }
    }

    rep(i,1,n){
        a[i][n+1]=a[i][n+1]*qpow(a[i][i])%mod;
    }
}

inline int ng(int x){
    return x&1?mod-1:1;
}

inline void init(){
    rep(s,1,tot){
        rep(i,1,n){
            rep(j,1,n+1){
                a[i][j]=0;
            }
        }

        rep(i,1,n){
            if(s>>(i-1)&1){
                a[i][i]=1;
            }
            else{
                int iv=d[i];
                a[i][i]=1;
                a[i][n+1]=1;

                for(int x:e[i]){
                    a[i][x]=(-iv+mod)%mod;
                }
            }
        }

        gauss(n);

        rep(i,1,n){
            f[i][s]=a[i][n+1]*ng(pcnt(s)+1)%mod;
        }
    }
}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    cin>>n>>m;

    rep(i,1,m){
        int u,v;
        cin>>u>>v;

        e[u].pb(v);
        e[v].pb(u);

        d[u]++,d[v]++;
    }

    rep(i,1,n){
        d[i]=qpow(d[i]);
    }

    tot=(1<<n)-1;

    init();

    rep(i,1,n){
        fwt(f[i],1<<n);
    }

    cin>>q;

    rep(i,1,q){
        int s=0,c,u;
        cin>>c;

        rep(j,1,c){
            int x;
            cin>>x;

            s|=1<<(x-1);
        }

        cin>>u;

        cout<<f[u][s]<<'\n';
    }

    return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...