zoukankan      html  css  js  c++  java
  • Luogu P4336 [SHOI2016]黑暗前的幻想乡 矩阵树定理+容斥原理

    真是菜到爆炸。。。。容斥写反(反正第一次写qwq)


    题意:$n-1$个公司,每个公司可以连一些边,求每个边让不同公司连的生成树方案数。

    矩阵树定理+容斥原理(注意到$n$不是很大)

    枚举公司参与与否的状态,每次重构矩阵,把参与连边的公司可以连的边写在矩阵中,然后求出方案。

    代码中的$Gauss()$是辗转相除求解,$Gauss2()$是通过求逆元求解(貌似我的辗转相除更快(雾))

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #define ll long long
    #define R register ll
    char B[1<<15],*S=B,*T=B;
    #define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
    const int M=1000000007;
    using namespace std;
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    int n,ans=0,C; ll a[20][20]; vector<pair<int,int> > q[20];
    #define pb push_back 
    inline int Gauss() { ll ans=1;
        for(R i=1;i<n;++i) {
            for(R j=i+1;j<n;++j) while(a[j][i]) {
                ll t=a[i][i]/a[j][i];
                for(R k=i;k<n;++k) (a[i][k]-=t*a[j][k])%=M;
                swap(a[i],a[j]); ans=-ans;
            } ans=(ans*a[i][i])%M; if(!ans) return 0;
        } return (ans+M)%M;
    } 
    inline ll Inv(int x) {
        if(x==1) return 1; if(x<1) return 0;
        return (M-M/x*Inv(M%x))%M;
    }
    inline int Gauss2() { register ll ans=1;
        for(R i=1;i<n;++i) for(R j=i+1;j<n;++j) {
            if(!a[i][i]) return 0; if(!a[j][i]) continue;
            register ll t=(ll)a[j][i]*Inv(a[i][i]%M)%M;
            for(R k=i;k<n;++k) a[j][k]=((a[j][k]-t*a[i][k])%M+M)%M;
        } for(R i=1;i<n;++i) ans=ans*a[i][i]%M; return ans;
    }
    signed main() { 
        n=g(); for(R i=1,x;i<n;++i) { x=g(); 
            for(R j=1,u,v;j<=x;++j) u=g(),v=g(),q[i].pb(make_pair(u,v));
        } C=1<<(n-1);
        for(R i=0;i<C;++i) { R cnt=0; memset(a,0,sizeof(a));
            for(R j=1;j<n;++j) if(i&(1<<j-1)) {
                for(R k=0,u,v;k<q[j].size();++k) 
                    u=q[j][k].first,v=q[j][k].second,
                    ++a[u][u],++a[v][v],--a[u][v],--a[v][u];
                ++cnt;
            } if((n-cnt)&1) ans=(ans+Gauss2())%M;
            else ans=(ans-Gauss2()+M)%M;
        } printf("%lld
    ",ans);
    }

    2019.06.02

  • 相关阅读:
    [PHP]socket的连接超时 与 读取/写入超时
    [PHP]引用返回与节省内存
    [PHP]实体类基类和序列化__sleep问题
    [PHP]日志处理error_log()函数和配置使用
    [PHP] 使用反射实现的控制反转
    [PHP] debug_backtrace()可以获取到代码的调用路径追踪
    [TCP/IP] TCP的传输连接管理
    [PHP] sys_get_temp_dir()和tempnam()函数报错与环境变量的配置问题
    [PHP] ubuntu下使用uuid扩展获取uuid
    [Linux] host dig nslookup查询域名的DNS解析
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10964640.html
Copyright © 2011-2022 走看看