题解:
把原图的边看作白边,其他边看作黑边做矩阵树。
根据矩阵树的意义,最后结果为所有边权的乘积,我们扩域把白边边权看作 1 1 ,黑边看做 x x ,那么最后得到的多项式 ≤k ≤ k 的项即为答案。
不过直接做太慢了,用 FFT F F T 也只能做到 n4logn n 4 log n ,考虑拉格朗日插值,做 n n 次矩阵树最后插出原多项式即可,时间复杂度 O(n4) O ( n 4 ) 。
const int N=55,mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod)?x+y-mod:x+y;}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b) {
int rs=1;
for(;b;b>>=1, a=mul(a,a)) if(b&1) rs=mul(rs,a);
return rs;
}
int n,fa[N],yc[N],f[N],g[N],a[N][N];
inline int det() {
for(int i=1;ifor(int j=1;jif(a[i][j]<0) a[i][j]+=mod;
int sgn=1;
for(int i=1;iint l;
for(l=i;lif(l==n) return 0;
if(l!=i) {
sgn=-sgn;
for(int j=i;jint inv=power(a[i][i],mod-2);
for(int j=i+1;jint t=mul(a[j][i],inv);
for(int k=i;kint rs=1;
for(int i=1;ireturn (sgn>0)?rs:mod-rs;
}
inline int calc(int x) {
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
if(fa[i]==j || fa[j]==i)
--a[i][j],--a[j][i],++a[i][i],++a[j][j];
else
a[i][j]-=x,a[j][i]-=x,a[i][i]+=x,a[j][j]+=x;
}
return det();
}
class TreeDistance {
public:
int countTrees(vector<int> p, int K) {
n=p.size()+1;
for(int i=2;i<=n;i++) fa[i]=p[i-2]+1;
for(int i=1;i<=n;i++) yc[i]=calc(i);
for(int i=1;i<=n;i++) {
memset(g,0,sizeof(g));
g[0]=1;
for(int j=1;j<=n;j++) {
if(i==j) continue;
int inv=power(add(i,mod-j),mod-2);
for(int k=n;k>=0;k--)
g[k]=add(mul(g[k],mul(mod-j,inv)),k?mul(g[k-1],inv):0);
}
for(int j=0;j<=n;j++)
f[j]=add(f[j],mul(g[j],yc[i]));
}
for(int i=1;i<=n;i++)
f[i]=add(f[i-1],f[i]);
return f[min(K,n)];
}
};