• BZOJ 4596: [Shoi2016]黑暗前的幻想乡 矩阵树定理+容斥


    求生成树方案的话要用矩阵树定理,然后这个容斥就是常见套路了吧. 

    code: 

    #include <cstring>
    #include <cstdio>
    #include <vector>   
    #include <algorithm>
    #define N 18     
    #define mod 1000000007        
    #define ll long long
    #define setIO(s) freopen(s".in","r",stdin)
    using namespace std;        
    int a[N][N],n,det[N][N][N],bu[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 INV(int x) { return qpow(x,mod-2); }
    int gauss()
    {
        int ans=1,i,j,k;   
        for(i=2;i<=n;++i)
        {
            k=i;
            for(j=i+1;j<=n;++j)  if(a[j][i]>a[k][i]) k=j; 
            if(k!=i) swap(a[i],a[k]),ans*=-1;  
            if(!a[i][i]) return 0;  
            int inv=INV(a[i][i]);      
            for(j=i+1;j<=n;++j)                      
            {
                int t=(ll)((ll)inv*a[j][i]%mod+mod)%mod;  
                for(k=i;k<=n;++k) a[j][k]=(ll)(a[j][k]%mod-(ll)t*a[i][k]%mod+mod)%mod;       
            }
        }
        if(ans<0) ans+=mod;   
        for(i=2;i<=n;++i) ans=(ll)((ll)ans*a[i][i]%mod+mod)%mod;  
        return ans; 
    }       
    // 度数-邻接矩阵        
    void build(int x) 
    {
        int i,j;    
        for(i=1;i<=n;++i) for(j=1;j<=n;++j) a[i][j]+=det[x][i][j];   
    }
    int main() 
    {     
        // setIO("input");    
        int i,j,m;     
        scanf("%d",&n);   
        for(i=1;i<=n-1;++i) 
        {    
            scanf("%d",&m);    
            for(j=1;j<=m;++j) 
            { 
                int x,y;  
                scanf("%d%d",&x,&y);  
                det[i][x][x]++;   
                det[i][y][y]++;   
                det[i][x][y]--;  
                det[i][y][x]--;            
            }
        }    
        for(i=0;i<N;++i) bu[i]=1<<i;                  
        int ans=0;   
        for(i=bu[n-1]-1;i>0;--i) 
        {      
            memset(a,0,sizeof(a));
            int siz=0;    
            for(j=0;bu[j]<=i;++j) if(bu[j]&i) build(j+1),++siz;   
            int tmp=gauss();    
            // printf("%d
    ",tmp);    
            int d=((n-1-siz)%2==0)?1:mod-1;   
            ans=(ll)(ans+(ll)d*tmp%mod+mod)%mod;      
        }
        printf("%d
    ",ans);     
        return 0;   
    }
    

      

  • 相关阅读:
    谈谈编译和运行
    全国车辆违章查询API文档及demo
    两款模拟键盘输入和鼠标点击的命令行工具
    利用AFNetworking框架去管理从聚合数据上面请求到的数据
    谈 API 的撰写
    谈 API 的撰写
    (四)Oracle条件查询,分页查询
    (三)Oracle字符串操作
    (二)Oracle数据库原理
    (一)Oracle安装详解
  • 原文地址:https://www.cnblogs.com/guangheli/p/12256815.html
Copyright © 2020-2023  润新知