数论+线性代数 插值+矩阵树 CF917D题解

题目大意

一张有 \(n\) 个节点的完全图,再给出这张图的一棵生成树,问该图有多少颗生成树和这颗生成树的公共边总共有 \(k\) 条,求助 \(0 \leq k \leq n-1\) 时所有 \(k\) 的答案。

做法

首先我们知道矩阵树定理求的是 所有生成树的边权之积的和。

那么我们设树边的边权为 \(x\),非树边的边权为 \(1\),若一棵生成树和该树有 \(k\) 条公共边,则该生成树的边权之积为 \(x^k\)。

求和之后的 \(k\) 次项就是答案了。

但是每一次行变换我们需要做 \(1\) 次乘法和 \(n\) 次减法,复杂度虽然是 \(O(n^4\log n)\) 的,但是如此大的常数即使是 CF 的机子也会 T。。。

我们换个思路,FFT 的运算过程就是 带入+差值,那我们把这个过程提到外面来做不就好了?

答案一定是一个 \(n-1\) 次多项式,根据代数基本定理,我们只需要 \(n\) 个点值就能把它插出来。

我们枚举 \(x\) 从 \(1\) 到 \(n\),对于每一个 \(x\) 跑一次矩阵树,复杂度 \(O(n^4)\)。

最后我们可以 \(O(n)\) 拉格朗日差值,也可以 \(O(n^3)\) 高斯消元,我写的是高斯消元,因为最近刷矩阵树逐渐熟悉了高斯消元(

code:

const int M=105,mod=1e9+7;
int n,u[M],v[M],x[M];
int G[M][M],Matrix[M][M];
inline int Add(const int&a,const int&b){
    return a+b>=mod?a+b-mod:a+b;
}
inline int Del(const int&a,const int&b){
    return a-b<0?a-b+mod:a-b;
}
inline int pow(int a,int b=mod-2){
    int ans=1;
    for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;
    return ans;
}
inline int Matrix_Tree(){
    register int i,j,k,d,inv,ans=1;
    for(i=2;i<=n;++i){
        inv=pow(Matrix[i][i]);
        for(j=i+1;j<=n;++j){
            d=1ll*Matrix[j][i]*inv%mod;
            for(k=i;k<=n;++k)Matrix[j][k]=Del(Matrix[j][k],1ll*d*Matrix[i][k]%mod);
        }
        ans=1ll*ans*Matrix[i][i]%mod;
    }
    return ans;
}
inline void Gauss(){
    register int i,j,k,d,inv;
    for(i=1;i<=n;++i){
        inv=pow(G[i][i]);
        for(j=1;j<=n;++j){
            if(i==j)continue;
            d=1ll*G[j][i]*inv%mod;
            for(k=i;k<=n+1;++k)G[j][k]=Del(G[j][k],1ll*d*G[i][k]%mod);
        }
    }
}
signed main(){
    register int i,j,k,X;
    scanf("%d",&n);
    for(i=1;i<=n;++i){
        for(j=1;j<=n;++j){
            if(i==j)G[i][j]=n-1;
            else G[i][j]=mod-1;
        }
    }
    for(i=1;i<n;++i)scanf("%d%d",u+i,v+i);
    for(i=1;i<=n;++i){
        for(j=1;j<=n;++j){
            for(k=1;k<=n;++k){
                Matrix[j][k]=G[j][k];
            }
        }
        x[i]=i;G[i][n+1]=Matrix_Tree();
        for(j=1;j<n;++j){
            ++G[u[j]][u[j]];++G[v[j]][v[j]];
            --G[u[j]][v[j]];--G[v[j]][u[j]];
        }
    }
    for(i=1;i<=n;++i){
        G[i][1]=1;X=x[i];
        for(j=2;j<=n;++j){
            G[i][j]=X;X=1ll*X*x[i]%mod;
        }
    }
    Gauss();
    for(i=1;i<=n;++i)printf("%d ",1ll*G[i][n+1]*pow(G[i][i])%mod);
}
上一篇:MODINT 模板


下一篇:Codeforces 135E - Weak Subsequence(分析性质+组合数学)