zoukankan      html  css  js  c++  java
  • CF917D Stranger Trees

    Description

    给定一棵有标号的树,求恰好与该树有 (k) 条边相同的树的个数。分别对 (kin[0,n)) 求值。

    Solution

    主要考察对矩阵树定理的理解程度。我们知道由矩阵树定理求得的矩阵的行列式的值是该图所有生成树中边权乘积的和,即

    [sum_{T}prod_{ein T} val_e ]

    如果把给定树的树边标成 (x),非树边标成 (1),那么一个生成树的所有边的权值积就是一个单项式 (1^p x^{n-1-p}),其中 (x) 的指数就蕴含了有多少条边是给定树的树边。通过这个很巧妙的方法,对所有这样的单项式求和,就得到一个多项式,其中 (x^k) 的系数就表示恰好有 (k) 条边相同的生成树个数。我们又知道一个 (n-1) 次多项式只需要 (n) 个点值就能被确定,所以分别令 (x=1dots n) 跑矩阵树定理,得到一个线性方程组。最后再高斯消元一下,就能得到多项式系数,即答案。

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    #define N 107
    #define Mod 1000000007
    #define ll long long
    
    int n;
    int X[N],Y[N];
    ll a[N][N],A[N][N],ans[N];
    
    ll qpow(ll x,ll y){
        ll ret=1,cnt=0;
        while(y>=(1<<cnt)){
            if(y&(1<<cnt)) ret=ret*x%Mod;
            x=x*x%Mod,cnt++;
        }
        return ret;
    }
    
    void build(){
        for(int i=1;i<=n;i++) a[i][i]=n-1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i!=j) a[i][j]=Mod-1;
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++)
            scanf("%d%d",&X[i],&Y[i]);
        for(int x=1;x<=n;x++){
            build(); 
            for(int i=1;i<n;i++){
                int u=X[i],v=Y[i];
                a[u][u]+=x-1,a[v][v]+=x-1;
                a[u][v]=a[v][u]=Mod-x;
            }
            int m=n-1; ll ans=1,op=1;
            for(int i=1;i<=m;i++){
                int p=i;
                for(;p<=n;p++) if(a[p][i]) break;
                if(p!=i) swap(a[p],a[i]),op=-op;
                ll inv=qpow(a[i][i],Mod-2);
                for(int j=i+1;j<=n;j++){
                    ll mul=a[j][i]*inv%Mod;
                    for(int k=i;k<=n;k++)
                        a[j][k]=(a[j][k]-a[i][k]*mul%Mod+Mod)%Mod;
                }
                ans=(ans*a[i][i]%Mod+Mod)%Mod;
            }
            A[x][n+1]=(ans*op%Mod+Mod)%Mod; A[x][1]=1;
            for(int i=2;i<=n;i++) A[x][i]=A[x][i-1]*x%Mod;
        }
        for(int i=1;i<=n;i++){
            int p=0;
            for(p=i;p<n;p++) if(A[p][i]) break;
            if(p!=i) swap(A[i],A[p]);
            ll Inv=qpow(A[i][i],Mod-2);
            for(int j=n+1;j>=i;j--) A[i][j]=A[i][j]*Inv%Mod;
            for(int j=i+1;j<=n;j++)
                for(int k=n+1;k>=i;k--)
                    A[j][k]=(A[j][k]-A[i][k]*A[j][i]%Mod+Mod)%Mod;
        }
        ans[n]=A[n][n+1];
        for(int i=n-1;i;i--){
            ans[i]=A[i][n+1];
            for(int j=n;j>i;j--)
                ans[i]=(ans[i]-ans[j]*A[i][j]%Mod+Mod)%Mod;
        }
        for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
    }
    
  • 相关阅读:
    Strange RadioButton group behavior with ToolBar
    在XAML中为ItemsControl定义分组,适合mvvm绑定
    如何编写无法维护的代码 让自己稳拿铁饭碗 ;-)
    WPF 应用程序资源、内容和数据文件
    XNA+WPF solution worked
    object转List<XXX>的问题
    VS2013 执行Enable-Migrations,产生错误的解决办法
    WPF 为 PasswordBox 控件添加水印,最低级版
    为 ItemsControl 类型的控件提供行号,mvvm模式 绑定集合
    把父窗体设置为桌面,显示桌面时程序仍然能显示
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14470594.html
Copyright © 2011-2022 走看看