JZOJ5233 【GDOI模拟8.5】概率博弈 树形dp
来源:互联网 发布:mac上好用的office软件 编辑:程序博客网 时间:2024/06/02 07:02
妈耶,改这题各种失误,清空都能清错,本来清x然后清空了儿子,服了。
区间题做多了下意识leaf[1]-i+1
服气。
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,保证给出的是一棵合法的树。
wwtdalao的题目。
据gjx大爷说是经典题= =,很常见的套路。
就是在树上dp,问了hhh才切,看来我还是很菜= =
首先贴个题解:
那么我们就可以直接dp了。
设f为图中的G。
那么我们先统计出每个节点为根的叶子结点个数,然后开始dp。
边界条件f[x][1][0]=f[x][0][1]=1,x为叶子。
对于当前结点x,枚举他的子节点(子树),进行合并。
枚举的第一个直接赋值,然后其他的合并分类讨论。
然后枚举i,j表示进行合并的两颗树中有多少个0,然后对于合并时相连的节点的0/1讨论。
如果dep[x]&1,由小A操作,那么只有x=0,y=0(连接的两个节点)时F[x]=0(注意是大F)否则都为1,因为是取max。
反之只有x=1,y=1的时候F[X]=1;因为是取min。
然后就可以直接更新了。
答案统计就是f[1][i][1]*fac[i]*fac[leaf[1]-i]
因为0和1的排列顺序不固定,所以用阶乘计算。
#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=5e3+5;const int mo=1e9+7;typedef long long ll;int n,m;int g[N][N][2],tot;int fa[N],leaf[N],fac[N];bool bo[N];int f[N][N][2],head[N],next[N<<1],go[N<<1];inline void add(int x,int y){ go[++tot]=y; next[tot]=head[x]; head[x]=tot;}inline void dfs1(int x){ bool flag=1; for(int i=head[x];i;i=next[i]) { int v=go[i]; if (v!=fa[x]) { flag=0; fa[v]=x; dfs1(v); leaf[x]+=leaf[v]; } } if(flag)leaf[x]=1; bo[x]=flag;}inline void dfs(int x,int opt){ if(bo[x]) { f[x][1][0]=1; f[x][0][1]=1; return; } for(int i=head[x];i;i=next[i]) { int v=go[i]; if (v!=fa[x]) { dfs(v,1-opt); } } int num=0,sum=0; for(int i=head[x];i;i=next[i]) { int v=go[i]; if (v!=fa[x]) { num++; if (num==1)memcpy(f[x],f[v],sizeof(f[x])); else { fo(j,0,leaf[x])g[x][j][0]=g[x][j][1]=0; fo(k,0,leaf[v]) { fd(j,leaf[x],0) { if (j+k>leaf[x])continue; if (opt==0) { g[x][j+k][0]=(ll)(g[x][j+k][0]+1ll*f[v][k][0]*f[x][j][0]%mo)%mo; g[x][j+k][1]=(ll)(g[x][j+k][1]+1ll*f[v][k][0]*f[x][j][1]%mo)%mo; g[x][j+k][1]=(ll)(g[x][j+k][1]+1ll*f[v][k][1]*f[x][j][0]%mo)%mo; g[x][j+k][1]=(ll)(g[x][j+k][1]+1ll*f[v][k][1]*f[x][j][1]%mo)%mo; } else { g[x][j+k][0]=(ll)(g[x][j+k][0]+1ll*f[v][k][0]*f[x][j][0]%mo)%mo; g[x][j+k][0]=(ll)(g[x][j+k][0]+1ll*f[v][k][0]*f[x][j][1]%mo)%mo; g[x][j+k][0]=(ll)(g[x][j+k][0]+1ll*f[v][k][1]*f[x][j][0]%mo)%mo; g[x][j+k][1]=(ll)(g[x][j+k][1]+1ll*f[v][k][1]*f[x][j][1]%mo)%mo; } } } memcpy(f[x],g[x],sizeof(f[x])); } sum+=leaf[v]; } }}int main(){ freopen("game.in","r",stdin); freopen("game.out","w",stdout); scanf("%d",&n); fo(i,1,n-1) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(1); dfs(1,0); fac[0]=1; fo(i,1,N)fac[i]=1ll*fac[i-1]*i%mo; int ans=0; fo(i,0,leaf[1]) ans=(ans+1ll*fac[i]*f[1][i][1]%mo*fac[leaf[1]-i]%mo)%mo; printf("%d\n",ans);}
- JZOJ5233 【GDOI模拟8.5】概率博弈 树形dp
- 【JZOJ5233】【GDOI模拟8.5】概率博弈
- JZOJ5233【GDOI模拟】概率博弈
- 【BZOJ3566】概率充电器,树形概率DP
- bzoj3566:概率充电器(树形概率dp)
- hdu 4035 Maze 概率DP+树形DP
- HDU 4035 Maze 概率dp+树形dp
- 【BZOJ3566】【SHOI2014】概率充电器 树形DP 概率DP
- bzoj 3566: [SHOI2014]概率充电器 概率dp+树形dp
- BZOJ3566:概率充电器(树形dp & 概率dp)
- 2010 成都Regional H 博弈,概率dp
- NOIP模拟 探险 【树形dp】
- (简单) 树形dp+概率 POJ 3071 Football
- (概率+树形)dp HDU 4035 Maze
- bzoj 3566: [SHOI2014]概率充电器 树形DP
- hdu 4035 Maze (树形概率dp)
- HDU 4443 Lost 树形概率DP
- codeforces 500d 树形dp和概率
- Getting Started with Vuforia for Android Development 开始使用Vuforia进行Android开发
- 开发Rtmp推流端开发库的几种选择方案
- C# SQL Server的封装(SQLDataAdapter等)之一(共二)
- 排序1——冒泡,选择排序
- 【C语言】指针
- JZOJ5233 【GDOI模拟8.5】概率博弈 树形dp
- VMware虚拟机搭MAC系统
- Beanutils基本用法
- Agti—Net
- 读书笔记(一)——《Java核心技术卷一》第三章Java的基本程序设计结构
- java 类初始化顺序
- tensorflow模型量化
- 文章标题
- 小写数字金额转大写