CF917D-Stranger Trees【矩陣樹定理,高斯消元】
阿新 • • 發佈:2021-01-23
技術標籤:數論and數學codeforces矩陣樹定理高斯消元
正題
題目連結:https://www.luogu.com.cn/problem/CF917D
題目大意
給出
n
n
n個點的一棵樹,對於每個
k
k
k求有多少個
n
n
n個點的樹滿足與給出的樹恰好有
k
k
k條邊重合。
解題思路
矩陣樹有一個統計所有樹邊權和的和用法,就是把變數變成一個形如 w x + 1 wx+1 wx+1的多項式,這樣一次項係數的值就表示了固定選擇一條邊的 w w w時其他邊的方案數之和。
這題我們可以同理,對於在給出數上的邊是
x
x
x,而其他就是
1
1
1。那麼最後詢問
x
k
x^k
xk的係數就是答案了。
如果暴力套 NTT \text{NTT} NTT不僅麻煩,而且跑的很慢過不了本題,考慮另一種求係數的方法。
我們假設答案是一個形如 F ( x ) = ∑ i = 0 n − 1 a i x i F(x)=\sum_{i=0}^{n-1}a_ix^i F(x)=∑i=0n−1aixi的 n n n次項式,那麼我們如果把 n n n個 x x x的值直接帶入求出 F F F,然後用待定係數法的話我們就可以列出 n n n個方程從而解出這個 n n n項式的每一個係數。
時間複雜度 O ( n 4 ) O(n^4) O(n4)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=110,P=1e9+7;
ll n,x[N],y[N];
ll power(ll x,ll b){
ll ans=1;
while(b){
if(b&1)ans=ans*x%P;
x=x*x%P;b>>=1;
}
return ans;
}
namespace Guass{
ll a[N][N],b[ N];
void solve(){
for(ll i=1;i<=n;i++){
ll z=i;
for(ll j=i;j<=n;j++)
if(a[j][i]){z=j;break;}
swap(a[i],a[z]);swap(b[i],b[z]);
ll inv=power(a[i][i],P-2);
for(ll j=i;j<=n;j++)
a[i][j]=a[i][j]*inv%P;
b[i]=b[i]*inv%P;
for(ll j=i+1;j<=n;j++){
ll rate=P-a[j][i];
for(ll k=i;k<=n;k++)
(a[j][k]+=rate*a[i][k]%P)%=P;
(b[j]+=rate*b[i]%P)%=P;
}
}
for(ll i=n;i>=1;i--){
for(ll j=i+1;j<=n;j++)
(b[i]+=P-b[j]*a[i][j]%P)%=P;
}
return;
}
}
namespace Matrix{
ll a[N][N];
ll det(){
ll f=1,ans=1;
for(ll i=1;i<n;i++){
ll z=i;
for(ll j=i;j<n;j++)
if(a[j][i]){
if(j!=i)f=-f;
z=j; break;
}
swap(a[i],a[z]);
ll inv=power(a[i][i],P-2);
ans=ans*a[i][i]%P;
for(ll j=i;j<n;j++)
a[i][j]=a[i][j]*inv%P;
for(ll j=i+1;j<n;j++){
ll rate=P-a[j][i];
for(ll k=i;k<n;k++)
(a[j][k]+=rate*a[i][k]%P)%=P;
}
}
return ans*f;
}
void solve(ll w){
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
a[i][j]=P-1;
for(ll i=1;i<=n;i++)a[i][i]=n-1;
for(ll i=1;i<n;i++){
a[x[i]][x[i]]+=w-1;
a[y[i]][y[i]]+=w-1;
a[x[i]][y[i]]=P-w;
a[y[i]][x[i]]=P-w;
}
Guass::b[w]=det();
for(ll i=1,p=1;i<=n;i++,p=p*w%P)
Guass::a[w][i]=p;
return;
}
}
signed main(){
scanf("%lld",&n);
for(ll i=1;i<n;i++)
scanf("%lld%lld",&x[i],&y[i]);
for(ll i=1;i<=n;i++)Matrix::solve(i);
Guass::solve();
for(ll i=1;i<=n;i++)
printf("%lld ",Guass::b[i]);
return 0;
}