题意:
问n个点有m个叶子的带标号无根树数量。n,m<=1000000
题解:
注意到(为啥我就注意不到QAQ)一个节点是叶子当且仅当其在prufer编码中没有出现。那么答案就是Cmn∗S(n−m),其中S(k)表示有多少长度为n-2的序列满足这里面恰好出现了k种元素。这个可以用容斥原理来做。
代码
#include <bits/stdc++.h>
typedef long long ll;
const int N = 1000010;
const int MOD = 1e9 + 7;
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int ksm(int x,int y)
{
int res = 1;
while (y)
{
if (y & 1)
res = 1ll * x * res % MOD;
x = 1ll * x * x % MOD;
y >>= 1;
}
return res;
}
int jc[N],ny[N];
int getC(int n,int m)
{
return 1ll * jc[n] * ny[m] % MOD * ny[n - m] % MOD;
}
int n,m;
int main()
{
n = read(), m = read();
if (n == 1 || n == 2)
{
puts("1");
return 0;
}
jc[0] = jc[1] = 1;
ny[0] = ny[1] = 1;
for (int i = 2; i <= n; i++)
{
jc[i] = 1ll * jc[i - 1] * i % MOD;
ny[i] = 1ll * (MOD - MOD / i) * ny[MOD % i] % MOD;
}
for (int i = 2; i <= n; i++)
{
ny[i] = 1ll * ny[i - 1] * ny[i] % MOD;
}
int ans = 0;
for (int i = n - m; i >= 1; i--)
{
if (i % 2 == (n - m) % 2)
ans += 1ll * ksm(i, n - 2) * getC(n - m, i) % MOD, ans -= ans >= MOD ? MOD : 0;
else ans += MOD - 1ll * ksm(i, n - 2) * getC(n - m, i) % MOD, ans -= ans >= MOD ? MOD : 0;
}
ans = 1ll * ans * getC(n, m) % MOD;
printf("%d\n",ans);
}