首先我们设
�
(
�
,
�
)
F(u,v) 表示
�
u 和
�
v 连通的时候,
�
u 往上蹦一下的情况数量。
显而易见,答案是
∑
�
=
1
�
∑
�
=
1
�
�
(
�
,
�
)
∑
i=1
n
∑
j=1
n
F(i,j)。
然后你发现,如果一条路长度相同,那么他并没有什么不一样的,因为道路内的没有实际差异,道路外的我不在乎,也没有实际差异。
所以你决定枚举长度
�
l,假设
�
�
G
l
为所有长度为
�
l 的路径的
�
F,假设
�
�
�
�
cnt
l
表示长度为
�
l 的路径数量,那么现在答案是
∑
�
=
1
�
�
�
�
�
�
�
∑
l=1
n
cnt
l
G
l
。
�
�
�
�
cnt
l
我们很方便计算,考虑
�
�
G
l
怎么计算。
先枚举
�
w 表示第
�
w 层的时候路径端点开始蹦。
然后你发现总共要在路径中做
�
�
wl 次操作,每个点恰好做
�
w 次。
这个不难,首先打标签全排列,然后再去标签。
然后假设是第
�
k 次操作拿下的。
那就是,
�
−
1
k−1 次操作中安排
�
�
wl 次操作,然后剩下
�
−
1
−
�
�
k−1−wl 次操作,可以选择路径外的所有点。
剩下
�
−
�
m−k 次操作,可以选择所有点因为目的已经达到了后面什么样子不在乎了。
式子就长这样:
�
�
=
∑
�
�
<
�
(
�
�
)
!
(
�
!
)
�
∑
�
=
�
�
+
1
�
�
�
−
1
�
�
(
�
−
�
)
�
−
1
−
�
�
�
�
−
�
G
l
=
wl
(w!)
l
(wl)!
k=wl+1
∑
m
C
k−1
wl
(n−l)
k−1−wl
n
m−k
然后你发现直接嗯算就是
�
2
ln
�
m
2
lnn 的,非常的愚蠢,我们需要来优化他。
首先就是那个低能组合数,我们必须把他拿下来,但是很明显拿不下来,那我们就考虑整
�
k 次操作在路径上。
�
�
=
∑
�
�
<
�
(
�
�
)
!
(
�
!
)
�
∑
�
=
�
�
+
1
�
�
�
�
(
�
)
�
−
1
−
�
�
(
�
−
�
)
�
−
�
G
l
=
wl
(w!)
l
(wl)!
k=wl+1
∑
m
C
m
k
(l)
k−1−wl
(n−l)
m−k
这个式子非常好看,但是还不够,我们容不得
�
w 在后面出现!
所以我们把他变成了这个样子。
�
�
=
∑
�
�
<
�
(
�
�
)
!
(
�
!
)
�
�
−
�
�
∑
�
=
�
�
+
1
�
�
�
�
(
�
)
�
−
1
(
�
−
�
)
�
−
�
G
l
=
wl
(w!)
l
(wl)!
l
−wl
k=wl+1
∑
m
C
m
k
(l)
k−1
(n−l)
m−k
很好,后面没有
�
w 了,这意味着后面的式子只与
�
k 和
�
l 有关了。
但是还不够,写一下就会发现难写,所以我们再化一下。
�
�
=
∑
�
�
<
�
(
�
�
)
!
(
�
!
)
�
�
−
�
�
∑
�
=
�
�
+
1
�
�
�
�
(
�
)
(
�
−
�
)
+
(
�
−
1
)
(
�
−
�
)
�
−
�
G
l
=
wl
(w!)
l
(wl)!
l
−wl
k=wl+1
∑
m
C
m
k
(l)
(k−m)+(m−1)
(n−l)
m−k
�
�
=
∑
�
�
<
�
(
�
�
)
!
(
�
!
)
�
�
−
�
�
∑
�
=
�
�
+
1
�
�
�
�
(
�
)
(
�
−
1
)
(
�
−
�
�
)
�
−
�
G
l
=
wl
(w!)
l
(wl)!
l
−wl
k=wl+1
∑
m
C
m
k
(l)
(m−1)
(
l
n−l
)
m−k
�
�
=
∑
�
�
<
�
(
�
�
)
!
(
�
!
)
�
�
�
−
�
�
−
1
∑
�
=
�
�
+
1
�
�
�
�
(
�
−
�
�
)
�
−
�
G
l
=
wl
(w!)
l
(wl)!
l
m−wl−1
k=wl+1
∑
m
C
m
k
(
l
n−l
)
m−k
那我们直接对于每一个
�
l 预处理一遍这些式子,然后后缀和,就可以直接求了。
天才的想法!
时间复杂度
�
(
�
�
+
�
ln
�
)
O(nm+mlnn)。
#include
#define int long long
using namespace std;
const int P=1000000007;
const int MAXN=200005;
int n,m;
vector
int Cnt[1500];
int father[1500][11];
int dep[1500];
int Jc[MAXN];
int InvJc[MAXN];
int Pre[MAXN];
int Suf[MAXN];
int ans;
int Co[MAXN];
int power(int x,int y=P-2){
if(y==0)return 1;
int tmp=power(x,y>>1);
if(y&1)return tmp*tmp%P*x%P;
else return tmp*tmp%P;
}
void dfs(int cur,int fa){
dep[cur]=dep[fa]+1;
father[cur][0]=fa;
for(int i=1;i<11;i++){
father[cur][i]=father[father[cur][i-1]][i-1];
}
for(int i=0;i
if(v==fa)continue;
dfs(v,cur);
}
return;
}
int LCA(int x,int y){
if(dep[x]
if(dep[father[x][i]]>=dep[y]){
x=father[x][i];
}
}
if(x==y)return x;
for(int i=10;i>=0;i--){
if(father[x][i]^father[y][i]){
x=father[x][i];
y=father[y][i];
}
}
return father[x][0];
}
int dis(int x,int y){
int lca=LCA(x,y);
return dep[x]+dep[y]-dep[lca]-dep[father[lca][0]];
}
int C(int n,int m){
return Jc[n]*InvJc[m]%P*InvJc[n-m]%P;
}
signed main(){
scanf("%lld%lld",&n,&m);
Jc[0]=1;
InvJc[0]=1;
for(int i=1;i<=200000;i++){
Jc[i]=Jc[i-1]*i%P;
InvJc[i]=power(Jc[i]);
}
for(int i=0;i<=m;i++){
Co[i]=C(m,i);
}
for(int i=1;i
scanf("%lld%lld",&u,&v);
ljb[u].push_back(v);
ljb[v].push_back(u);
}
dfs(1,0);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int fw=dis(i,j);
if(fw<1||fw>n){
return j;
}
assert(fw>=1&&fw<=n);
Cnt[fw]++;
}
}
for(int l=1;l<=n;l++){
int Fuck=(n-l)*power(l)%P;
int D=1;
for(int i=m;i>=0;i--){
Suf[i]=(Suf[i+1]+C(m,i)*D%P)%P;
D=D*Fuck%P;
}
int S=0;
for(int w=0;w*l
S=(S+dinner)%P;
}
ans=(ans+S*Cnt[l]%P)%P;
}
printf("%lld",ans%P);
return 0;
}