题目
思路
考试时候想了一个性质
首先算每条边的贡献
假设一条边一边点集大小为
s
s
s,在其中有
x
x
x 个人
显然有
m
i
n
(
x
,
m
−
x
)
min(x,m-x)
min(x,m−x) 个人经过
贡献为
∑
x
=
1
m
m
i
n
(
x
,
m
−
x
)
(
s
x
)
(
n
−
s
m
−
x
)
\sum_{x=1}^mmin(x,m-x)\dbinom{s}{x}\dbinom{n-s}{m-x}
∑x=1mmin(x,m−x)(xs)(m−xn−s)
发现有
m
i
n
min
min 不好做,考虑去掉
m
i
n
min
min
记
k
=
⌊
m
−
1
2
⌋
k=\lfloor\frac{m-1}{2}\rfloor
k=⌊2m−1⌋
f
(
s
)
=
∑
x
=
1
k
x
(
s
x
)
(
n
−
s
m
−
x
)
f(s)=\sum_{x=1}^kx\dbinom{s}{x}\dbinom{n-s}{m-x}
f(s)=∑x=1kx(xs)(m−xn−s)
当
m
m
m 是奇数时候贡献为
f
(
s
)
+
f
(
n
−
s
)
f(s)+f(n-s)
f(s)+f(n−s)
当
m
m
m 是偶数时候贡献为
f
(
s
)
+
f
(
n
−
s
)
+
m
/
2
(
s
m
/
2
)
(
n
−
s
m
/
2
)
f(s)+f(n-s)+m/2\dbinom{s}{m/2}\dbinom{n-s}{m/2}
f(s)+f(n−s)+m/2(m/2s)(m/2n−s)
f
(
s
)
=
∑
x
=
1
k
x
s
!
x
!
(
s
−
x
)
!
(
n
−
s
m
−
x
)
=
f
(
s
)
=
s
∑
x
=
1
k
(
s
−
1
)
!
(
x
−
1
)
!
(
s
−
x
)
!
(
n
−
s
m
−
x
)
f
(
s
)
=
s
∑
x
=
1
k
(
s
−
1
x
−
1
)
(
n
−
s
m
−
x
)
=
s
⋅
g
(
s
)
f(s)=\sum_{x=1}^kx\frac{s!}{x!(s-x)!}\dbinom{n-s}{m-x}=\\f(s)=s\sum_{x=1}^k\frac{(s-1)!}{(x-1)!(s-x)!}\dbinom{n-s}{m-x}\\ f(s)=s\sum_{x=1}^k\dbinom{s-1}{x-1}\dbinom{n-s}{m-x}=s\cdot g(s)
f(s)=∑x=1kxx!(s−x)!s!(m−xn−s)=f(s)=s∑x=1k(x−1)!(s−x)!(s−1)!(m−xn−s)f(s)=s∑x=1k(x−1s−1)(m−xn−s)=s⋅g(s)
考虑
g
(
s
)
g(s)
g(s) 的组合意义:
在长度为
n
−
1
n-1
n−1 的序列中选择
m
−
1
m-1
m−1 个数,并且要求在前
s
−
1
s-1
s−1 最多选
k
−
1
k-1
k−1 个
考虑递推,发现本质上只会算少选择第
s
s
s 个和在前
s
−
1
s-1
s−1 个选
k
−
1
k-1
k−1 个的方案数即后
[
s
+
1
,
n
−
1
]
[s+1,n-1]
[s+1,n−1] 选择
m
−
k
−
1
m-k-1
m−k−1 个:
g
(
s
+
1
)
=
g
(
s
)
−
(
s
−
1
k
−
1
)
(
n
−
s
−
1
m
−
k
−
1
)
g(s+1)=g(s)-\dbinom{s-1}{k-1}\dbinom{n-s-1}{m-k-1}
g(s+1)=g(s)−(k−1s−1)(m−k−1n−s−1)
注意
k
=
0
k=0
k=0 时候
g
(
1
)
=
0
g(1)=0
g(1)=0
时间复杂度
O
(
n
)
O(n)
O(n)
代码
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<climits>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
int read(){
bool f=0;int x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define mp make_pair
const int MAXN=1000000;
const int Mod=(int)(1e9+7);
int Mul(LL x,int y){x*=y;return x>=Mod?x%Mod:x;}
int Sub(int x,int y){x-=y;return x<0?x+Mod:x;}
int Add(int x,int y){x+=y;return x>=Mod?x-Mod:x;}
int fac[MAXN+5],inv[MAXN+5];
int Pow(int x,int y){
int ret=1;
while(y){
if(y&1) ret=Mul(ret,x);
x=Mul(x,x),y>>=1;
}
return ret;
}
int C(int n,int m){if(n<m||m<0) return 0;return Mul(fac[n],Mul(inv[m],inv[n-m]));}
int n,m,f[MAXN+5];
int ans,siz[MAXN+5];
struct Edge{
int v,nxt;
}edge[2*MAXN+5];
int ecnt,head[MAXN+5];
void Addedge(int u,int v){
edge[++ecnt]=(Edge){v,head[u]},head[u]=ecnt;
edge[++ecnt]=(Edge){u,head[v]},head[v]=ecnt;
return ;
}
void DFS(int u,int fa){
siz[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(v==fa) continue;
DFS(v,u),siz[u]+=siz[v];
int s=siz[v];
ans=Add(ans,Add(f[s],f[n-s]));
if(!(m&1))
ans=Add(ans,Mul(s,Mul(C(s-1,m/2-1),C(n-s,m/2))));
}
return ;
}
int main(){
freopen("meeting.in","r",stdin);
freopen("meeting.out","w",stdout);
n=read(),m=read();
for(int u=2;u<=n;u++)
Addedge(u,read());
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=Mul(fac[i-1],i);
inv[n]=Pow(fac[n],Mod-2);
for(int i=n-1;i>=0;i--)
inv[i]=Mul(inv[i+1],i+1);
int k=(m-1)/2;
if(!k) f[1]=0;
else f[1]=C(n-1,m-1);
for(int i=2;i<=n;i++)
f[i]=Sub(f[i-1],Mul(C(i-2,k-1),C(n-i,m-k-1)));
for(int i=2;i<=n;i++)
f[i]=Mul(f[i],i);
DFS(1,0);
printf("%d\n",ans);
return 0;
}