• CF917D Stranger Trees 矩阵树定理+拉格朗日插值


    先对完全图构建矩阵,然后将原树上的边 $(x,y)$ 在矩阵中的边权标记成 $x^1$,其余边权为 $1$.  

    矩阵树定理求的是所有生成树边权乘积之和,那么要是可以对含 $x$ 的矩阵求行列式的话可以直接得出答案.   

    但是复杂度太高,而且难写(写不了)    

    所以用 $n$ 个不同的整数来替换那个 $x^1$,然后跑出来 $n$ 个结果,用拉格朗日插值还原出多项式的系数即可.    

    #include <cstdio>  
    #include <vector>
    #include <cstring>
    #include <algorithm>       
    #define N 103
    #define ll long long 
    #define mod 1000000007
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;      
    int n;    
    int A[N],B[N];  
    int f[N][N],k1[N],k2[N],ans[N]; 
    int deg[N][N],con[N][N],a[N][N];   
    struct point { 
        int x,y;  
        point(int x=0,int y=0):x(x),y(y){}  
    }p[N];  
    int qpow(int x,int y) { 
        int tmp=1; 
        for(;y;y>>=1,x=(ll)x*x%mod) 
            if(y&1) {   
                tmp=(ll)tmp*x%mod;  
            }
        return tmp; 
    }
    int get_inv(int x) { 
        return qpow(x,mod-2);  
    }     
    int ADD(int x,int y) { 
        return (ll)(x+y)%mod; 
    } 
    int DEC(int x,int y) { 
        return (ll)(x-y+mod)%mod;  
    }  
    int MUL(int x,int y) { 
        return (ll)x*y%mod;   
    }
    int gauss() {  
        int ans=1;  
        for(int i=1;i<n;++i) { 
            for(int j=i+1;j<n;++j) {    
                while(a[j][i]) { 
                    int t=a[i][i]/a[j][i];  
                    for(int k=i;k<n;++k) {
                        a[i][k]=DEC(a[i][k],MUL(t,a[j][k]));          
                    }
                    swap(a[j],a[i]);   
                    ans=(ll)ans*(mod-1)%mod;    
                }
            }
            if(!a[i][i]) { 
                return 0;  
            }
        }
        for(int i=1;i<n;++i) { 
            ans=(ll)ans*a[i][i]%mod;    
        }
        return ans;   
    }         
    int cal(int val) {  
        for(int i=1;i<=n;++i) {  
            for(int j=1;j<=n;++j) { 
                a[i][j]=mod-1; 
            }
        }   
        for(int i=1;i<=n;++i) { 
            a[i][i]=n-1;    
        }
        for(int i=1;i<n;++i) {  
            int x=A[i],y=B[i];                        
            a[x][x]=(ll)(DEC(a[x][x],1)+val)%mod;    
            a[y][y]=(ll)(DEC(a[y][y],1)+val)%mod;    
            a[x][y]=(ll)(a[x][y]+1-val+mod)%mod;  
            a[y][x]=(ll)(a[y][x]+1-val+mod)%mod; 
        }
        return gauss();   
    }
    void init() {  
        f[0][0]=1;   
        for(int i=1;i<=n;++i) { 
            for(int j=1;j<=i;++j) 
                f[i][j]=ADD(f[i-1][j-1],MUL(f[i-1][j],mod-p[i].x));     
            f[i][0]=(ll)f[i-1][0]*(mod-p[i].x)%mod;   
        }
    }
    int main() {  
        // setIO("input");   
        scanf("%d",&n);  
        int x,y,z; 
        for(int i=1;i<n;++i) {            
            scanf("%d%d",&A[i],&B[i]);  
        }
        for(int i=1;i<=n;++i) {  
            p[i].x=i;   
            p[i].y=cal(i);  
        }     
        init();  
        for(int i=1;i<=n;++i) {  
            int inv=1;  
            for(int j=1;j<=n;++j) {     
                if(i!=j) inv=(ll)inv*(p[i].x-p[j].x+mod)%mod;   
            }
            inv=get_inv(inv);       
            for(int j=0;j<=n;++j) {
                k2[j]=f[n][j]; 
            }
            for(int j=n-1;j>=0;--j) {
                k1[j]=k2[j+1];     
                k2[j]=ADD(k2[j],MUL(p[i].x,k1[j]));   
            }                 
            for(int j=0;j<=n-1;++j) { 
                ans[j]=ADD(ans[j],(ll)k1[j]*inv%mod*p[i].y%mod);   
            }
        }     
        for(int i=0;i<n;++i) { 
            printf("%d ",ans[i]);   
        }
        return 0;  
    }
    

      

  • 相关阅读:
    windows中echo的用法
    通过phpMyAdmin写入MySQL,获取webshell
    底部小鱼特效
    kali Linux的简单介绍
    Kali安装gmpy2
    利用kali生成字典的三种方式
    利用kali嗅探HTTP网页用户账户密码
    永恒之蓝(ms017-010)漏洞利用
    如何使用最新Microsoft Edge打开Flash页面
    结对第二次作业
  • 原文地址:https://www.cnblogs.com/guangheli/p/13331406.html
Copyright © 2020-2023  润新知