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

    LOJ #2542. 「PKUWC 2018」随机游走(最值反演 + 树上期望dp)

    其实不是很难啦

    min-max容斥既视感

    设f[x]表示从x走到S中第一个点的期望步数

    f[x]=1/d[x]*(f[fa[x]])+∑1/d[x]*(f[ch[x]])+1

    这个有环

    利用f[x]=A*f[fa[x]]+B的套路代换

    得到A,B的递推式

    对于x=rt,f[fa[x]]=0,所以f[x]=Bx了

    对于叶子,结果恰好也是A=1,B=1

    可以2^n枚举S,再O(nlogn)log有逆元,得到答案

    对于Q,直接2^n枚举子集

    O((nlogn+Q)*2^n))

    因为2^n跑不满,可以过。

    或者,预处理答案,O(1)回答

    O((nlogn)+3^n+Q))

    代码(法一):

    #include<bits/stdc++.h>
    #define il inline
    #define reg register int
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=20;
    const int mod=998244353;
    int n,q;
    int rt;
    int qm(int x,int y){
        int ret=1;
        while(y){
            if(y&1) ret=(ll)ret*x%mod;
            x=(ll)x*x%mod;
            y>>=1;
        }
        return ret;
    }
    int A[N],B[N];
    int ans[1<<18];
    int sz[1<<18];
    int S;
    int d[N];
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    void dfs(int x,int fa){
        //A[x]=0;B[x]=0;
        if(S&(1<<(x-1))) {
            A[x]=0,B[x]=0;
            return;
        }
        int sb=0,sa=0;
        int son=0;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa) continue;
            ++son;
            dfs(y,x);
            sb=(sb+B[y])%mod;
            sa=(sa+A[y])%mod;
        }
        
        if(son){
            A[x]=qm((d[x]-sa+mod)%mod,mod-2);
            B[x]=((ll)sb+d[x])*qm((d[x]-sa+mod)%mod,mod-2)%mod;
        }else{
            A[x]=1;
            B[x]=1;
        }
    }
    int main(){
        rd(n);rd(q);rd(rt);
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);
            ++d[x];++d[y];
            add(x,y);add(y,x);
        }
        for(S=1;S<(1<<n);++S){
            sz[S]=sz[S>>1]+(S&1);
            dfs(rt,0);
            ans[S]=B[rt];
        //    cout<<" S "<<S<<" : "<<ans[S]<<" A "<<A[rt]<<endl;
        }
        int k;
        while(q--){
            S=0;
            rd(k);
            for(reg i=1;i<=k;++i){
                rd(x);
                S|=(1<<(x-1));
            }
            ll op=0;
            for(int tmp=S;tmp;tmp=S&(tmp-1)){
                if(sz[tmp]&1){
                    op=((ll)op+ans[tmp])%mod;
                }else{
                    op=((ll)op-ans[tmp]+mod)%mod;
                }
            }
            printf("%lld
    ",op);
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/1/20 21:36:25
    */
  • 相关阅读:
    android openGl视频
    《jQuery权威指南》学习笔记之第2章 jQuery选择器
    RobHess的SIFT源码分析:综述
    building android/ubuntu-touch on 32bit machine
    Android开发(24)---安卓中实现多线程下载(带进度条和百分比)
    创建Sdcard
    POJ 1033 Defragment
    [C++STDlib基础]关于C标准输入输出的操作——C++标准库头文件<cstdio>
    机器学习实战决策树之眼镜男买眼镜
    protubuffer for windows配置指南!
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10296423.html
Copyright © 2011-2022 走看看