CF917D Stranger Trees【矩阵树定理,高斯消元】

题目链接:洛谷

题目大意:给定一个$n$个节点的树$T$,令$ans_k=\sum_{T'}[|T\cap T'|=k]$,即有$k$条边重合。输出$ans_0,ans_1,\ldots,ans_{n-1}$.

数据范围:$1\leq n\leq 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 }
CF917D

猜你喜欢

转载自www.cnblogs.com/AThousandMoons/p/10962738.html