zoukankan      html  css  js  c++  java
  • 「PKUWC2018」随机游走

    传送门

    Description

    给定一棵 (n) 个结点的树,你从点 (x) 出发,每次等概率随机选择一条与所在点相邻的边走过去。

    (Q) 次询问,每次询问给定一个集合 (S),求如果从 (x) 出发一直随机游走,直到点集 (S) 中所有点都至少经过一次的话,期望游走几步。

    特别地,点 (x)(即起点)视为一开始就被经过了一次。

    答案对 (998244353) 取模。

    Solution

    题目是让我们求一个集合最后一个中最后一个到达的点的期望,换句话说,就是到达时间的(max)的期望

    考虑(MinMax)容斥:

    [max{S}=sum_{T⊆S}(-1)^{|T|-1}min{ T} ]

    这样,我们就只要枚举一下子集就行了。

    考虑如何求第一次访问某个集合的时间期望

    • (f[i][S])表示从(i)出发,第一次访问到(S)的时间期望

    • 显然有如下转移:

    • [f[i][S]=1+frac{1}{deg_i}sum_{j}f[j][S],i和j有边相连 ]

    • 这样显然既要考虑父亲还要考虑孩子,不可做,考虑把它化成:

    • [f[i][S]=A_if[fa_i][S]+B_i ]

    • 假设已经知道了所有的(和A_j和B_j),把它带到第一个式子里面,就可以求出(和A_i和B_i)

    • 推导就不说了,注意当(i)属于(S)时,(A_i=B_i=0),因为(x)是根,所以(f[x][S]=B_x)

    我们再考虑如何求子集和

    • (g[i][S])表示前(i)位与(S)相同,后(N-i)为是(S)的子集的集合的和
    • (S)的第(i)为是(0),则(g[i][S]=g[i+1][S])
    • (S)的第(i)为是(1),则(g[i][S]=g[i+1][S]+g[i+1][S - (1<<i)])

    Code 

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define mod 998244353
    inline void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
    inline void dec(int &x,int y){x-=y;if(x<0)x+=mod;}
    inline int fpow(int x,int m){int r=1;for(;m;x=1ll*x*x%mod,m>>=1)if(m&1)r=1ll*r*x%mod;return r;}
    int N,Q,S,A[1<<18],B[1<<18],d[20],bit[1<<18],f[1<<18];
    struct edge{int to,nex;}e[40];int en,hr[20];
    inline void ins(int f,int t)
    {
        e[++en]=(edge){t,hr[f]};hr[f]=en;
        e[++en]=(edge){f,hr[t]};hr[t]=en;
    }
    
    void dfs(int x,int f,int Set)
    {
        if(Set>>x-1&1) return (void)(A[x]=B[x]=0);
        register int i;A[x]=B[x]=d[x];
        for(i=hr[x];i;i=e[i].nex)if(f^e[i].to)
        {
            dfs(e[i].to,x,Set);
            dec(A[x],A[e[i].to]);
            add(B[x],B[e[i].to]); 
        }
        A[x]=fpow(A[x],mod-2);
        B[x]=1ll*B[x]*A[x]%mod;
    }
    int main()
    {
        N=read();Q=read();S=read();
        register int x,y,i,j;
        for(i=1;i<N;++i) x=read(),y=read(),++d[x],++d[y],ins(x,y);
        for(i=1;i<(1<<N);++i)
        {
            bit[i]=bit[i>>1]+(i&1);
            dfs(S,0,i);f[i]=bit[i]&1?B[S]:mod-B[S];
        }
        
        for(i=N-1;~i;--i) for(j=(1<<N)-1;~j;--j) if(j>>i&1) add(f[j],f[j^(1<<i)]);
        while(Q--)
        {
            x=read();y=0;while(x--)y|=1<<read()-1;
            printf("%d
    ",f[y]);
        }
        return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    Android应用开发基础篇(16)-----ScaleGestureDetector(缩放手势检测)
    Android应用开发基础篇(15)-----URL(获取指定网址里的图片)
    Android应用开发基础篇(14)-----自定义标题栏
    Android应用开发提高篇(6)-----FaceDetector(人脸检测)
    Android应用开发提高篇(5)-----Camera使用
    Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)
    Android应用开发基础篇(13)-----GestureDetector(手势识别)
    Android应用开发基础篇(12)-----Socket通信
    Android应用开发实例篇(1)-----简易涂鸦板
    Android应用开发提高篇(3)-----传感器(Sensor)编程
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10285588.html
Copyright © 2011-2022 走看看