zoukankan      html  css  js  c++  java
  • [SHOI2016] 黑暗前的幻想乡

    题意:

    有n个点,你想修n-1条路将这n个点联通。有n-1家建筑公司,每家建筑公司可以修m条边。

    你希望让每家建筑公司恰好修一条边。求修路方案数对$10^{9}+7$取模的值。

    $nleq 17,mleq frac{n(n-1)}{2}$。

    题解:

    挺水的一道题。看到“每家恰好修一条边”就想到容斥。

    显然总方案数$N=N(随便修)-N(至少一家不修)=N(随便修)-N(钦定一家不修)+N(钦定两家不修)-cdots$。

    那么考虑枚举每家公司是否修的二进制状态,我们只需要把所有为1的公司的边拿出来建图,然后求该图的生成树个数即可。

    复杂度$O(2^{n}n^{3})$,我也不知道怎么回事就过了。

    套路:

    • 形如“恰好/至少/至多k个满足条件”的计数问题$ ightarrow$容斥。

    代码:

    #include<bits/stdc++.h>
    #define maxn 20
    #define maxm 500005
    #define inf 0x7fffffff
    #define mod 1000000007
    #define ll long long
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    struct edge{ll u,v;};
    vector<edge> E[maxn];
    ll A[maxn][maxn];
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline ll pw(ll a,ll b){ll r=1;while(b)r=(b&1)?r*a%mod:r,a=a*a%mod,b>>=1;return r;}
    inline ll inv(ll x){return pw(x,mod-2);}
    
    inline ll Gauss(ll n){
        ll ans=1;
        for(rint j=1;j<=n;j++){
            for(rint i=j;i<=n;i++)
                if(A[i][j]!=0){
                    for(rint k=1;k<=n;k++) swap(A[i][k],A[j][k]);
                    if(i!=j) ans=ans*(mod-1)%mod; break;
                }
            if(A[j][j]==0) return 0;
            for(rint i=1;i<=n;i++)
                if(i!=j && A[i][j]!=0){
                    ll x=A[i][j]*inv(A[j][j])%mod;
                    for(rint k=1;k<=n;k++) A[i][k]=(A[i][k]-A[j][k]*x%mod+mod)%mod;
                }
        }
        for(rint i=1;i<=n;i++) ans=ans*A[i][i]%mod;
        return ans;
    }
    
    int main(){
        ll n=read(),ans=0;
        for(rint i=1;i<n;i++){
            ll m=read();
            for(rint j=1;j<=m;j++){
                ll u=read(),v=read();
                E[i].push_back((edge){u,v});
            }
        }
        for(rint s=0,a=1;s<(1<<(n-1));s++){
            a=1,memset(A,0,sizeof(A)); 
            for(rint i=1;i<n;i++){
                if(!(s&(1<<i-1))){a=a*(mod-1)%mod;continue;}
                for(rint j=0;j<E[i].size();j++){
                    ll u=E[i][j].u,v=E[i][j].v;
                    A[u][u]=(A[u][u]+1)%mod,A[v][v]=(A[v][v]+1)%mod;
                    A[u][v]=(A[u][v]+mod-1)%mod,A[v][u]=(A[v][u]+mod-1)%mod;
                }
            }
            ans=(ans+a*Gauss(n-1)%mod)%mod;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    黑暗前的幻想乡
  • 相关阅读:
    android studio Cannot resolve symbol '@drawable/XXX'等问题解决办法
    android面试
    Android动态增量
    客户端传递Cookie到WebView中
    Android事件传递机制
    Activity状态保存的两种方式
    Activity Window View之间的关系
    Git学习笔记
    Android Log命令常用方法
    ListView 中点击Item中的Button删除当前行
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13246217.html
Copyright © 2011-2022 走看看