zoukankan      html  css  js  c++  java
  • [树形dp] Jzoj P5233 概率博弈

    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,保证给出的是一棵合法的树。

    题解

    • 我们假设k为最后取的树,我们把一个叶子>=k染成1,把<k的染成0
    • 考虑一下树形dp,设f[i][j][0/1]为以i为根的子树中有j个1当前点为0/1的方案数
    • 那么对于当前是基层,也就是小A取值,f[i][j][0]= ∏f[son[x]][k][0],f[i][j][1]=。对于偶层,也就是小B取值也是一样的
    • 枚举前面儿子的叶子然后枚举当前要合并的儿子的叶子背包一下
    • 我们可以枚举k,也就是子树中1的个数,所以我们最后要记入答案是∑(f[1][k][1]-f[1][k+1][1])k! (size[1]-k)!

    代码

     1 #include <cstdio>
     2 #define ll long long
     3 using namespace std;
     4 const ll N=5010,mo=1e9+7;
     5 struct edge { int to,from; }e[N*2];
     6 ll f[N][N][2],head[N],size[N],jc[N],g[N],ans,n,cnt,r;
     7 void insert(int x,int y) { e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt; }
     8 ll ksm(ll a,ll b){ for (r=1;b;b>>=1,a=a*a%mo) if (b&1) r=r*a%mo; return r;}
     9 ll C(ll x,ll y) { return jc[y]*ksm(jc[y-x],mo-2)%mo*ksm(jc[x],mo-2)%mo; }
    10 void dfs(int d,int x,int y,int l,int r)
    11 {
    12     if (d>g[0]) { (f[x][r][l]+=y)%=mo; return; }
    13     for (int i=0;i<=size[g[d]];i++) if (f[g[d]][i][l]) dfs(d+1,x,y*f[g[d]][i][l]%mo,l,r+i);
    14 }
    15 void dp(int x,int y,int k)
    16 {
    17     for (int i=head[x];i;i=e[i].from) if (e[i].to!=y) dp(e[i].to,x,k^1),size[x]+=size[e[i].to];
    18     g[0]=0; for (int i=head[x];i;i=e[i].from) if (e[i].to!=y) g[++g[0]]=e[i].to;
    19     if (size[x])
    20     {
    21         dfs(1,x,1,k,0);
    22         for (int i=0;i<=size[x];i++) f[x][i][k^1]=(C(i,size[x])-f[x][i][k]+mo)%mo;
    23     }
    24     else size[x]++,f[x][0][0]=f[x][1][1]=1;
    25 }
    26 int main()
    27 {
    28     freopen("game.in","r",stdin),freopen("game.out","w",stdout),scanf("%lld",&n);
    29     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
    30     jc[0]=1; for (int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mo; dp(1,0,0);
    31     for (int i=0;i<=size[1];i++) (ans+=f[1][i][1]*jc[i]%mo*jc[size[1]-i]%mo)%=mo;
    32     printf("%lld",ans);
    33 }
  • 相关阅读:
    http参数传递方式
    Api接口管理工具推荐
    IntelliJ IDEA 插件推荐
    spring服务器接收参数格式
    SSM框架的常用注解整理
    Java map 详解
    遍历Map集合四中方法
    bean对应mapper.xml字段
    Java简历与面试
    SQL的case when then else end语句的用法
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10296073.html
Copyright © 2011-2022 走看看