\(\text{Description}\)

小白和小黑的学校在举办趣味运动会,其中有一个项目是在树形迷宫里进行竞技。迷宫是一个由 \(𝑛\) 个节点,\(𝑛 − 1\) 条长度为 \(1\) 的可双向通行的边组成的图,保证任意两点可互相到达。

小白和小黑所在的队伍一共有 \(𝑚\) 个人,竞技开始时会随机进入树上 \(𝑚\)互不相同 的节点,他们通过无线通讯设备确定一个集合点,然后所有人沿最短路径走到集合点,花费的代价为所有人走的路径长度之和。 为了取得竞技的胜利,他们需要最小化花费的代价。

然而他们并不知道他们最终会进入哪个节点,所以你需要对于每种不同的情况计算最小代价并求出总和。方案可能很多,请你输出答案对 \(1000000007\) 取模的结果。 两种情况不同,当且仅当对于存在某个节点 \(𝑖\),在一种情况中节点 \(𝑖\) 上有一个人, 而另一种情况中 \(𝑖\) 上没有人。

\(n,m\le 10^6\).

\(\text{Solution}\)

直接考虑肯定是让人头大的,对于这种不定点的树上问题,一个常见的思路是考虑边的贡献。

假设一条边两端关键点个数分别为 \(x,m-x\),如果有 \(x\le m-x\),肯定会把集合点设在 \(m-x\) 的那个连通块里,这样它只会被经过 \(x\) 次。

假设一条边两侧分别有 \(s,n-s\) 个点,那么这条边的贡献就是:

\[\sum_{x=1}^{m-1}\text C(s,x)\times \text C(n-s,m-x)\times \min(x,m-x) \]

这样肯定过不去,考虑优化掉 \(\min\),其实如果强制 \(x\le m-x\) 就有 \(x\le \lfloor\frac{m}{2}\rfloor\). 考虑 \(x\) 范围只有 \([1,m)\),把 \(m\) 为偶的 \(x=\frac{m}{2}\) 情况刨开,就有:

\[\sum_{x=1}^{\lfloor\frac{m-1}{2}\rfloor} \text C(s,x)\times \text C(n-s,m-x)\times x +\sum_{x=1}^{\lfloor\frac{m-1}{2}\rfloor} \text C(n-s,x)\times \text C(s,m-x)\times x+[m\bmod 2=0]\cdot \text C(s,\frac{m}{2})\times \text C(n-s,\frac{m}{2})\times \frac{m}{2} \]

那么我们只用快速求

\[\sum_{x=1}^{\lfloor\frac{m-1}{2}\rfloor} \text C(s,x)\times \text C(n-s,m-x)\times x \]

后面带的 \(x\) 不利于化简,我们可以 利用组合数 消去。

\(\lfloor\frac{m-1}{2}\rfloor=k\),上柿就变成:

\[s\cdot\sum_{x=1}^{k} \text C(s-1,x-1)\times \text C(n-s,m-x) \]

并令其为 \(s\cdot g(s)\).

这个柿子有组合意义:在 \(n-1\) 个球里选 \(m-1\) 个球,保证前 \(s-1\) 个球中最多选 \(k-1\) 个球的方案数(以后遇到 \(\binom{x}{y}\cdot \binom{n-x}{m-y}\) 的情况都可以这样转化)。显然 \(g(s+1)\) 相对于 \(g(s)\) 只少了在前 \(s-1\) 选了 \(k-1\) 个球,又选了第 \(s\) 个球的情况(考虑限制更紧,肯定会变少),这种方案数可以表示为 \(\text C(s-1,k-1)\times \text C(n-1-s,m-1-k)\):在前 \(s-1\) 个球中选了 \(k-1\) 个球,\(n-1-s\) 表示除了前 \(s\) 个球的球数,\(m-1-k\) 表示前面 \(s\) 个球选了 \(k\) 个,那么后面 \(n-1-s\) 个球要选 \(m-1-k\) 个,显然这样强制了选了第 \(s\) 个球。

\(\text{Code}\)

#include <cstdio>

#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}

const int mod=1e9+7,maxn=1e6+5; 

int n,m,fac[maxn],ifac[maxn],k,siz[maxn],ans,g[maxn];
int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt;

void addEdge(int u,int v) {
	nxt[++cnt]=head[u],to[cnt]=v,head[u]=cnt;
	nxt[++cnt]=head[v],to[cnt]=u,head[v]=cnt;
}

int qkpow(int x,int y) {
	int r=1;
	while(y) {
		if(y&1) r=1ll*r*x%mod;
		x=1ll*x*x%mod; y>>=1;
	}
	return r;
}

void init() {
	fac[0]=1;
	rep(i,1,n) fac[i]=1ll*fac[i-1]*i%mod;
	ifac[n]=qkpow(fac[n],mod-2);
	fep(i,n-1,0) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
}

int C(int x,int y) {
	if(x<y) return 0;
	return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;
}

void dfs(int u,int fa) {
	siz[u]=1;
	erep(i,u) {
		if(v==fa) continue;
		dfs(v,u);
		siz[u]+=siz[v];
		ans=((ans+g[siz[v]])%mod+g[n-siz[v]])%mod;
		if(!(m&1)) ans=(ans+1ll*C(siz[v],m>>1)*C(n-siz[v],m>>1)%mod*(m>>1)%mod)%mod;
	} 
}

int main() {
//	freopen("meeting.in", "r", stdin);
//	freopen("meeting.out", "w", stdout);
	int x;
	n=read(9),m=read(9); k=m-1>>1; init();
	rep(i,2,n) x=read(9),addEdge(x,i);
	if(k>=1) g[1]=C(n-1,m-1); // 注意特判这个时候没有数值
	rep(i,1,n-1) g[i+1]=(g[i]-1ll*C(i-1,k-1)*C(n-1-i,m-1-k)%mod+mod)%mod;
	rep(i,1,n) g[i]=1ll*g[i]*i%mod;
	dfs(1,0);
	print(ans,'\n');
	return 0;
} 
posted on 2020-11-29 15:15  Oxide  阅读(180)  评论(0编辑  收藏  举报