博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

【树形动规】【NOIP模拟10-21】概率博弈

Description

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

Input Format

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

Output Format

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

Sample Input & Sample Output

【输入输出样例1】 game.in  game.out 5 1 2 2 3  1 4 2 5 14

【输入输出样例2】 game.in  game.out 10 10 7 7 6 10 2 2 3   3 8 3 1 6 9 7 5 1 4

Solution

首先,我们设f[i][j][x]为以i为根的存在j个1的子树最终到达叶子大于等于x的方案数;
如果我们要求等于x的方案数 很显然 直接用
f[i][j][x]-f[i][j][x+1];
那我们要求期望,也就是要求结果*方案数*概率的总和
概率为1/m!,而题目中又要求将答案*m!,刚好相乘为1;
而结果*方案数=1*(f[i][j][1]-f[i][j][2]) +2*(f[i][j][2]-f[i][j][3]) ...
如上式,最终结果就是f[i][j][1]的总和;
接下来考虑如何转移,对于每个叶子,假设它大于等于x,我们将其设为1,否则为0;
然后就转化成了背包问题,对于小A,肯定尽量走1,小B尽量走0,
而只有无法走1或无法走0的情况 小A才会选择0,小B才会选择1;
所以 考虑当前子树时 我们把全是0或全是1的方案数计算出来也就是
f[i][j][0]这个状态的转移;
而f[i][j][1]直接通过总方案数-全是0或全是1的方案数得到;
最后我们就会得到f[1][j][1]也就是整棵树中存在j个1最后得到1的方案数
然后我们给这个树上的1和0编上号,所以最后答案*j的阶乘以及(m-j)的阶乘;

#include<cstdio>
#include<cstring>

const int yh=1e9+7;
int n,ans;
int head[5005],num;
int f[5005][5005][2],g[5005][2];
int fac[5005];

struct edge
{
    int next,to;
}e[10005];

void add(int x,int y)
{
    e[++num].next=head[x];
    e[num].to=y;
    head[x]=num;
}

int dfs(int u,int fa,int p)
{
    int Su=0,Sv,tot;
    for (int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if (v==fa) continue;
        Sv=dfs(v,u,p^1);
        if (!Su) 
        {
            memcpy(f[u],f[v],sizeof f[u]);
            Su+=Sv;
            continue;
        }
        memset(g,0,sizeof g);
        for (int j=0;j<=Su;j++)
            for (int k=0;k<=Sv;k++)
            {
                tot=j+k;
                g[tot][p^1]=(g[tot][p^1]+1ll*f[u][j][p^1]*f[v][k][p^1])%yh;
                g[tot][p]=(g[tot][p]+1ll*(f[u][j][p^1]+f[u][j][p])*(f[v][k][p^1]+f[v][k][p])-(1ll*f[u][j][p^1]*f[v][k][p^1]))%yh;
            }
        memcpy(f[u],g,sizeof f[u]);
        Su+=Sv;
    }
    if (!Su)
    {
        Su++;
        f[u][0][0]=f[u][1][1]=1;
    }
    return Su;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    int m=dfs(1,0,1);
    fac[0]=1;
    for (int i=1;i<=m;i++)    fac[i]=(1ll*fac[i-1]*i)%yh;
    for (int i=1;i<=m;i++)    ans=((ans+(1ll*fac[i]*fac[m-i])%yh*f[1][i][1])%yh)%yh;
    printf("%d",ans);
}

 

posted @ 2017-10-23 21:51  JadeDark  阅读(260)  评论(0编辑  收藏  举报