zoukankan      html  css  js  c++  java
  • [期望DP][树形DP]JZOJ 5233 概率博弈

    Description

    小A和小B在玩游戏。这个游戏是这样的:
    有一棵n个点的以1为根的有根树,叶子有权值。假设有m个叶子,那么树上每个叶子的权值序列就是一个1->m 的排列。
    一开始在1号点有一颗棋子。两人轮流将这颗棋子移向其当前位置的一个儿子。假如棋子到达叶子,游戏结束,最终获得的权值为所在叶子对应权值。
    小A希望最后的权值尽量大,小B希望尽量小。小A是先手。
    在玩了很多局游戏后,小B对其中绝大多数局游戏的结果不满意,他觉得是小A对叶子权值做了手脚。于是他一怒之下,决定将叶子的权值随机排列。现在小B想知道,假如叶子的权值是随机排列的(即叶子权值的每种排列都以等概率出现),那么游戏期望的结果是多少?
    请输出答案乘上m! 对10^9+7取模的结果,显然这是一个整数。
     

    Input

    输入文件名为game.in。
    第一行包含一个整数n。
    接下来n-1行,每行两个整数u,v,表示有一条连接节点u,v的边。

    Output

    输出文件名为game.out。
    输出一个整数,表示答案。
     

    Sample Input

    输入1:
    5
    1 2
    2 3
    1 4
    2 5
    
    输入2:
    10
    10 7
    7 6
    10 2
    2 3
    3 8
    3 1
    6 9
    7 5
    1 4

    Sample Output

    输出1:
    14
    
    输出2:
    74
     

    Data Constraint

    对于10%的数据,n<=5
    对于30%的数据,n<=10
    对于60%的数据, n<=50
    对于100%的数据,n<=5000,保证给出的是一棵合法的树。

    分析

    我们发现如果要直接按权值求方案未免太难,我们不妨设最终答案为x,则小于等于x的权值设为0,大于的设为1

    设f[i][j][0/1]为在以i为根的子树中,有j个叶子节点为0,且i选择到的是0/1的期望

    那么转移是比较显然的,可以用一个DFS枚举从子节点传上来的叶子数量再转移(O(n)复杂度)

    然后对于层数我们显然小A或小B一定只会取1或0,那么另一个怎么求呢?我们只需要求出当前j与子树内叶子总数的组合数再-得到的情况即可

    最后我们统计答案时还需要考虑排列,所以需要乘上i!*(sz-i)!

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const int N=5e3+10;
    const ll P=1e9+7;
    struct Edge {
        int u,v,nx;
    }g[2*N];
    int cnt,list[N],sz[N],a[N];
    ll f[N][N][2],fact[N],ans;
    int n,m,size;
    
    void Add(int u,int v) {
        g[++cnt]=(Edge){u,v,list[u]};list[u]=cnt;
    }
    
    ll Power(ll x,ll y) {ll ans=1ll;for (;y;y>>=1,(x*=x)%=P) if (y&1) (ans*=x)%=P;return ans;}
    
    ll C(ll n,ll m) {return fact[n]*Power(fact[m],P-2)%P*Power(fact[n-m],P-2)%P;}
    
    void DFS(int dep,int u,int now,int cont,ll e) {
        if (dep>size) {(f[u][cont][now]+=e)%=P;return;}
        for (int i=0;i<=sz[a[dep]];i++) if (f[a[dep]][i][now]) DFS(dep+1,u,now,cont+i,e*f[a[dep]][i][now]%P);
    }
    
    void DFS(int u,int fa,int dep) {
        for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) DFS(g[i].v,u,!dep),sz[u]+=sz[g[i].v];
        size=0;for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) a[++size]=g[i].v;
        if (sz[u]) {
            DFS(1,u,dep,0,1ll);
            for (int i=0;i<=sz[u];i++) f[u][i][!dep]=((C(sz[u],i)-f[u][i][dep])%P+P)%P;
        }
        else sz[u]=1,f[u][0][0]=f[u][1][1]=1;
    }
    
    int main() {
        freopen("game.in","r",stdin);
        freopen("game.out","w",stdout);
        scanf("%d",&n);
        fact[0]=1ll;
        for (int i=1;i<N;i++) fact[i]=1ll*fact[i-1]*i%P;
        for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),Add(u,v),Add(v,u);
        DFS(1,0,0);for (int i=0;i<=sz[1];i++) (ans+=f[1][i][1]*fact[i]%P*fact[sz[1]-i]%P)%=P;
        printf("%lld",ans);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    数30的小程序
    convert curl command into java HttpGet
    优秀技术文章转载备份 --- 变速原理
    用 c 调用 win-api 实现自动点击c# winform 程序 的按钮
    win 10 安装 glew 方法
    《想到什么更新什么系列》processing 性能优化
    processing 根据物体移动方向改变朝向
    openFrameworks 无法生成exe已经找不到dll的解决方案
    UE4 无法打开源文件“file_name.generated.h”(Cannot open source file name.generated.h)
    UE4 重新编译老版本的插件
  • 原文地址:https://www.cnblogs.com/mastervan/p/10301008.html
Copyright © 2011-2022 走看看