妈耶,改这题各种失误,清空都能清错,本来清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);
}