题意:
给定一个有 n n n 个结点的树,结点带标,分别求与其有 k ( 0 ≤ k < n ) k(0 \leq k \lt n) k(0≤k<n) 条相同边的树的数量,答案模 1 0 9 + 7 10^9 + 7 109+7。 ( n ≤ 100 ) (n \leq 100) (n≤100)
链接:
https://vjudge.net/problem/CodeForces-917D
解题思路:
也是个生成树计数的问题,但限制了 k k k 条边的出现,将给定的树边设为 x x x,那么再用矩阵树定理求得的方案数为关于 x x x 的 n − 1 n - 1 n−1 次多项式,对应 x x x 的幂次即为相同的边数。直接用多项式乘法、求逆解行列式不实际,那么枚举 n n n 个点,拉格朗日插值解出多项式系数即可。单次行列式求解 O ( n 3 l o g n ) O(n^3logn) O(n3logn),总复杂度 O ( n 4 l o g n ) O(n^4logn) O(n4logn)。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e2 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
ll qpow(ll a, ll b){
ll ret = 1;
while(b){
if(b & 1) ret = ret * a % mod;
a = a * a % mod;
b >>= 1;
}
return ret;
}
struct Lag{
ll xi[maxn], yi[maxn], a[maxn], lx[maxn], li[maxn], tp[maxn]; int n;
void mul(ll f[], int n, ll b){
for(int i = n; i > 0; --i) tp[i] = f[i], f[i] = f[i - 1];
tp[0] = f[0], f[0] = 0;
for(int i = 0; i <= n; ++i) f[i] = (f[i] + b * tp[i]) % mod;
}
void dev(ll f[], ll b, ll ret[]){
for(int i = 0; i <= n; ++i) tp[i] = f[i];
for(int i = n; i > 0; --i){
ret[i - 1] = tp[i];
tp[i - 1] = (tp[i - 1] - b * tp[i]) % mod;
}
}
void solve(){
for(int i = 0; i <= n; ++i) lx[i] = a[i] = 0;
lx[0] = 1;
for(int i = 1; i <= n; ++i) mul(lx, i, -xi[i]);
for(int i = 1; i <= n; ++i){
ll tmp = 1;
for(int j = 1; j <= n; ++j){
if(i == j) continue;
tmp = tmp * (xi[i] - xi[j]) % mod;
}
tmp = yi[i] * qpow(tmp, mod - 2) % mod;
dev(lx, -xi[i], li);
for(int j = 0; j < n; ++j) a[j] = (a[j] + tmp * li[j]) % mod;
}
for(int i = 0; i < n; ++i) a[i] = (a[i] + mod) % mod;
}
} lag;
struct MatTree{
ll K[maxn][maxn]; int n;
void init(int nn){
n = nn;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j) K[i][j] = 0;
}
void add(int u, int v, int w = 1, int t = 1){
t ? (K[u][u] += w) %= mod : (K[v][v] += w) %= mod;
(K[u][v] -= w) %= mod;
}
ll det(){
ll ret = 1;
for(int i = 1; i <= n; ++i){
for(int j = i + 1; j <= n; ++j){
while(K[j][i]){
ll t = K[i][i] / K[j][i];
for(int k = i; k <= n; ++k){
K[i][k] -= K[j][k] * t;
K[i][k] = (K[i][k] % mod + mod) % mod;
swap(K[i][k], K[j][k]);
}
ret = -ret;
}
}
if(!K[i][i]) return 0;
ret = ret * K[i][i] % mod;
}
return (ret + mod) % mod;
}
ll solve(int rt){
for(int i = 1; i <= n; ++i) K[rt][i] = K[i][rt] = 0;
K[rt][rt] = 1;
return det();
}
} mattr;
int G[maxn][maxn];
int n;
int main(){
ios::sync_with_stdio(0); cin.tie(0);
cin >> n;
for(int i = 1; i < n; ++i){
int u, v; cin >> u >> v;
G[u][v] = G[v][u] = 1;
}
lag.n = n;
for(int x = 0; x < n; ++x){
mattr.init(n);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
mattr.add(i, j, G[i][j] ? x : 1);
}
}
lag.xi[x + 1] = x;
lag.yi[x + 1] = mattr.solve(1);
}
lag.solve();
for(int i = 0; i < n; ++i){
cout << lag.a[i] << " ";
}
cout << endl;
return 0;
}