小A和小B在玩游戏。这个游戏是这样的:
有一棵n个点的以1为根的有根树,叶子有权值。假设有m个叶子,那么树上每个叶子的权值序列就是一个1->m 的排列。
一开始在1号点有一颗棋子。两人轮流将这颗棋子移向其当前位置的一个儿子。假如棋子到达叶子,游戏结束,最终获得的权值为所在叶子对应权值。
小A希望最后的权值尽量大,小B希望尽量小。小A是先手。
在玩了很多局游戏后,小B对其中绝大多数局游戏的结果不满意,他觉得是小A对叶子权值做了手脚。于是他一怒之下,决定将叶子的权值随机排列。现在小B想知道,假如叶子的权值是随机排列的(即叶子权值的每种排列都以等概率出现),那么游戏期望的结果是多少?
请输出答案乘上m! 对10^9+7取模的结果,显然这是一个整数。
这题有一个很套路的想法,就是我们考虑最后答案大于等于k的方案数,然后用k的方案数-k+1的方案数就是等于k的方案数。
那么大于等于k的方案数的讨论也有一个很套路的想法,就是对于所有大于等于k的权值设为1,其它设为0,然后向上合并,如果最后在根节点能合并出1,那么这种01染色方案就合法,然后再给0和1表上号就好了(0的个数的阶乘和1的个数的阶乘)
那么我们就设f[i][j][0,1]表示在第i个点,以它为根的子树的叶子节点填了j个0,当前这个点的颜色为0或1。
然后我们分层数来考虑,对于奇数层(从0层开始),那么它的儿子数有一个0,当前颜色就是0的,那么我们就用总方案-全都是1的个数来求,当前要是1的话,那么就把儿子的1做个背包,枚举前面儿子的叶子然后枚举当前要合并的儿子的叶子背包一下(这样是n^2的,相当于把所有的叶子两两之间匹配一下),对于偶数层也是一样的。
最后在根节点上恰好为k的方案,然后再标号就好了。
其实还有一种求答案的方法,我们要求的期望是 ∑x∗P(x)
那么其实在一个平面图上就相当于1P(1),2P(2),3P(3),…nP(n),上面的方法是竖着求的,那么我们考虑横着求,设 P′(x) 表示权值大于等于x的概率,那么答案就是 ∑P′(x) 和我们上面设的状态是一样的。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int maxn=5007,mo=1e9+7;
ll i,j,k,l,t,n,m;
ll first[maxn*2],last[maxn*2],next[maxn*2],num,pp;
ll ni[maxn],fact[maxn],ans,f[maxn][maxn][2],son[maxn];
void add(int x,int y){
last[++num]=y,next[num]=first[x],first[x]=num;
}
ll qsm(ll x,ll y){
ll z=1;
for(;y;y/=2,x=x*x%mo)if(y&1)z=x*z%mo;
return z;
}
ll c(ll x,ll y){
return fact[x]*ni[y]%mo*ni[x-y]%mo;
}
void dfs(int x,int y,int z){
int i,l=0;
rep(i,x){
if(last[i]!=y){
l++;dfs(last[i],x,z+1);
fod(k,son[x]+son[last[i]],0){
pp=0;
fo(j,0,son[last[i]]){
if(k-j<0)break;
if(z%2)(pp+=f[last[i]][j][1]*f[x][k-j][1]%mo)%=mo;
else(pp+=f[last[i]][j][0]*f[x][k-j][0]%mo)%=mo;
}
if(z%2)f[x][k][1]=pp;else f[x][k][0]=pp;
if(l==1){if(z%2)f[x][k][1]+=f[last[i]][k][1];else f[x][k][0]+=f[last[i]][k][0];}
}
son[x]+=son[last[i]];
}
}
if(!l)son[x]=1,f[x][0][1]=f[x][1][0]=1;
else{
fo(j,0,son[x])if(z%2)f[x][j][0]=(c(son[x],j)-f[x][j][1]+mo)%mo;else
f[x][j][1]=(c(son[x],j)-f[x][j][0]+mo)%mo;
}
}
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
fact[0]=ni[0]=1;fo(i,1,5000)fact[i]=fact[i-1]*i%mo;ni[5000]=qsm(fact[5000],mo-2);
fod(i,4999,1)ni[i]=ni[i+1]*(i+1)%mo;
scanf("%lld",&n);
fo(i,1,n-1)scanf("%lld%lld",&k,&l),add(k,l),add(l,k);
dfs(1,0,0);
fo(i,0,son[1]){
ans=(ans+f[1][i][1]*fact[i]%mo*fact[son[1]-i])%mo;
}
ans=(ans+mo)%mo;
printf("%lld\n",ans);
}