题目链接:洛谷
题目大意:给定一个$n$个节点的树$T$,令$ans_k=sum_{T'}[|Tcap T'|=k]$,即有$k$条边重合。输出$ans_0,ans_1,ldots,ans_{n-1}$.
数据范围:$1leq nleq 100$
这题的思路挺巧妙的,非常不错。
我们将$T$上的边的边权作为$x$,不在$T$上的边的边权设为$1$(一个完全图),然后用矩阵树定理算出所有生成树的边权之积之和,也就是$x^k$的系数就是$ans_k$,现在我们要求这个多项式。
但是运算一个多项式的行列式复杂度会高到爆炸,所以我们考虑插值,只需要$n$个点值就可以,这里我们取$x=1,2,ldots n$,然后用高斯消元算出这个多项式的系数就可以。(具体实现看代码)
时间复杂度$O(n^4)$。

1 #include<bits/stdc++.h> 2 #define Rint register int 3 using namespace std; 4 typedef long long LL; 5 const int N = 103, mod = 1e9 + 7; 6 int n, a[N][N], b[N][N]; 7 bool tree[N][N]; 8 inline int kasumi(int a, int b){ 9 int res = 1; 10 while(b){ 11 if(b & 1) res = (LL) res * a % mod; 12 a = (LL) a * a % mod; 13 b >>= 1; 14 } 15 return res; 16 } 17 inline int Gauss(){ 18 int res = 1; 19 for(Rint i = 1;i < n;i ++){ 20 for(Rint j = i + 1;j < n;j ++) 21 while(a[j][i]){ 22 int d = a[i][i] / a[j][i]; 23 for(Rint k = i;k < n;k ++) 24 a[i][k] = (a[i][k] - (LL) d * a[j][k] + mod) % mod; 25 swap(a[i], a[j]); 26 res = mod - res; 27 } 28 res = (LL) res * a[i][i] % mod; 29 if(!a[i][i]) return 0; 30 } 31 return res; 32 } 33 int main(){ 34 scanf("%d", &n); 35 for(Rint i = 1;i < n;i ++){ 36 int a, b; 37 scanf("%d%d", &a, &b); 38 tree[a][b] = tree[b][a] = true; 39 } 40 for(Rint k = 1;k <= n;k ++){ 41 for(Rint i = 1;i <= n;i ++){ 42 a[i][i] = 0; 43 for(Rint j = 1;j <= n;j ++){ 44 if(i != j){ 45 if(tree[i][j]){ 46 a[i][j] = mod - k; 47 a[i][i] = (a[i][i] + k) % mod; 48 } else { 49 a[i][j] = mod - 1; 50 a[i][i] = (a[i][i] + 1) % mod; 51 } 52 } 53 } 54 } 55 b[k][1] = 1; 56 for(Rint i = 2;i <= n;i ++) b[k][i] = (LL) b[k][i - 1] * k % mod; 57 b[k][n + 1] = Gauss(); 58 } 59 for(Rint i = 1;i <= n;i ++){ 60 int inv = kasumi(b[i][i], mod - 2); 61 for(Rint j = i + 1;j <= n + 1;j ++) 62 b[i][j] = (LL) b[i][j] * inv % mod; 63 for(Rint j = 1;j <= n;j ++) 64 if(i != j) 65 for(Rint k = i + 1;k <= n + 1;k ++) 66 b[j][k] = (b[j][k] - (LL) b[j][i] * b[i][k] % mod + mod) % mod; 67 } 68 for(Rint i = 1;i <= n;i ++) printf("%d ", b[i][n + 1]); 69 }