我们用 h_n 表示 n 个点的有根树的本质不同的个数,g_{n,m} 表示用 m 个点,组成若干互不相同的大小 \le n 的子树的方案数。
转移:
h_{n}=g_{n-1,n-1}\\
g_{n,m}=\sum\limits_{i=0}^{\min\{h_n,\lfloor \frac{m}{n}\rfloor \}}\binom{h_n}{i}\times g_{n-1,m-n\times i} \\
f_{n}=
\left\{
\begin{array}{cc}
g_{\frac{n-1}{2},n-1} & 2\nmid n \\
g_{\frac{n}{2}-1,n-1}+\binom{g_{\frac{n}{2}-1,\frac{n}{2}-1}}{2} & 2 | n \\
\end{array}
\right.
$f$ 的转移,就是要考虑一下树的重心的个数,分类讨论以下即可。
然后用 python 简单跑一下,发现 $n=266$ 的时候 $\sum\limits_{i=1}^{n}f_i$ 已经超过了 $10^{100}$,足够了,python 代码:
```python
import math
mod=int(1e9+7)
n=266
def C(n,m):
if 0>m or m>n:
return 0
ans=1
for i in range(m):
ans=ans*(n-i)//(i+1)
return ans
f=h=[0 for i in range(0,n+1)]
g=[[0 for j in range(0,n+1)] for i in range(0,n+1)]
g[0][0]=1
for i in range(1,n+1):
h[i]=g[i-1][i-1]
for j in range(0,n+1):
for k in range(j//i+1):
g[i][j]+=C(h[i],k)*g[i-1][j-i*k]
for i in range(1,n+1):
f[i]=g[(i-1)//2][i-1]
if i%2==0:
f[i]+=C(g[i//2-1][i//2-1],2)
print(i,f[i])
T=int(input())
for t in range(T):
m=int(input())
if m>1 and m<6:
print(-1)
continue
if m==6:
print(9)
continue
ans=m*(m-1)//2-m
res=0
for i in range(1,n+1):
if m<i:
break
cnt=min(m//i,f[i])
res+=cnt
m-=i*cnt
print((ans+res)%mod)
```
然后就套个高精度模板就行了,注意要压位,不然跑不过去。
```cpp
#include<bits/stdc++.h>
using namespace std;
/* struct bign (bigint=bigbig=__int128, block>=8) */
const int N=3e2,mod=1e9+7;
int T,n=266;
bign m,f[N],g[N][N],h[N];
bign C(bign n,int m){
if(0>m||bign(m)>n)return bign(0);
bign ans(1);
for(int i=0;i<m;i++){
ans=ans*(n-i)/(i+1);
}
return ans;
}
bign min(bign x,bign y){
return x<y?x:y;
}
int main(){
freopen(".in","r",stdin);
// freopen(".out","w",stdout);
g[0][0]=1;
for(int i=1;i<=n;i++){
h[i]=g[i-1][i-1];
for(int j=0;j<=n;j++){
for(int k=0;i*k<=j;k++){
g[i][j]+=C(h[i],k)*g[i-1][j-i*k];
}
}
}
for(int i=1;i<=n;i++){
f[i]=g[(i-1)/2][i-1];
if(i%2==0)f[i]+=C(g[i/2-1][i/2-1],2);
// debug(i,f[i]);
}
for(cin>>T;T--;){
cin>>m;
if(m>bign(1)&&m<bign(6)){
puts("-1");
continue;
}
if(m==bign(6)){
puts("9");
continue;
}
int ans=m%mod;
ans=(ans*(ans-1ll)/2-ans+mod)%mod;
for(int i=1;i<=n;i++){
if(m<bign(i))break;
bign cnt=min(m/i,f[i]);
(ans+=cnt%mod)%=mod;
m-=cnt*i;
}
printf("%d\n",ans);
}
return 0;
}
```
[我用的 bign 模板](https://www.cnblogs.com/A-zjzj/p/17191659.html)