1. 程式人生 > 其它 >CF917D-Stranger Trees【矩陣樹定理,高斯消元】

CF917D-Stranger Trees【矩陣樹定理,高斯消元】

技術標籤:數論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=0n1aixi 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; }