zoukankan      html  css  js  c++  java
  • 【LOJ】#2027. 「SHOI2016」黑暗前的幻想乡

    题解

    我一开始写的最小表示法写的插头dp,愉快地TLE成60分

    然后我觉得我就去看正解了!
    发现是容斥 + 矩阵树定理

    矩阵树定理对于有重边的图只要邻接矩阵的边数设置a[u][v]表示u,v之间有几条边就好

    我们枚举哪些公司不用,然后用矩阵树求一下生成几棵树,复杂度(2^{n - 1}(n - 1)^3)

    代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define MAXN 200005
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    const int MOD = 1000000007;
    int N,cnt[(1 << 17) + 5],D[18][18],len[25];
    pii E[25][505];
    int lowbit(int x) {
        return x & (-x);
    }
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    void Init() {
        read(N);
        int M,u,v;
        for(int i = 1 ; i < N ; ++i) {
    	read(M);len[i] = M;
    	for(int j = 1 ; j <= M ; ++j) {
    	    read(u);read(v);
    	    E[i][j] = mp(u,v);
    	}
        }
    }
    int fpow(int x,int c) {
        int res = 1,t = x;
        while(c) {
    	if(c & 1) res = mul(res,t);
    	t = mul(t,t);
    	c >>= 1;
        }
        return res;
    }
    int Guass() {
        int res = 1;
        for(int i = 2 ; i <= N ; ++i) {
    	int l = i;
    	if(!D[l][i]) {
    	    for(int j = i + 1 ; j <= N ; ++j) {
    		if(D[j][i]) {l = j;break;}
    	    }
    	}
    	if(!D[l][i]) return 0;
    	if(l != i) {
    	    res = -res;
    	    for(int j = i ; j <= N ; ++j) swap(D[l][j],D[i][j]);
    	}
    	for(int j = i + 1; j <= N ; ++j) {
    	    int t = mul(D[j][i],fpow(D[i][i],MOD - 2));
    	    for(int k = i ; k <= N ; ++k) {
    		D[j][k] = inc(D[j][k],MOD - mul(D[i][k],t));
    	    }
    	}
        }
        if(res == -1) res = MOD - 1;
        for(int i = 2 ; i <= N ; ++i) {
    	res = mul(res,D[i][i]);
        }
        return res;
    }
    int calc(int S) {
        memset(D,0,sizeof(D));
        for(int i = 1 ; i <= N - 1; ++i) {
    	if(S >> (i - 1) & 1) {
    	    for(int j = 1 ; j <= len[i] ; ++j) {
    		D[E[i][j].fi][E[i][j].se] -= 1;
    		D[E[i][j].se][E[i][j].fi] -= 1;
    		D[E[i][j].fi][E[i][j].fi]++;
    		D[E[i][j].se][E[i][j].se]++;
    	    }
    	}
        }
        for(int i = 2 ; i <= N; ++i) {
    	if(!D[i][i]) return 0;
    	for(int j = 2 ; j <= N ; ++j) {
    	    D[i][j] = inc(D[i][j],MOD);
    	}
        }
        return Guass();
    }
    void Solve() {
        int ans = 0;
        for(int S = 0 ; S < (1 << (N - 1)) ; ++S) {
    	if(S) cnt[S] = cnt[S - lowbit(S)] + 1;
    	if((N - 1 - cnt[S]) & 1) ans = inc(ans,MOD - calc(S));
    	else ans = inc(ans,calc(S));
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Init();
        Solve();
    }
    
  • 相关阅读:
    WCF发布后的地址中域名与IP地址的问题
    asp.net判断字符串是否包含特殊字符
    silverlight中DataGrid错误:data未定义
    变电所、分区所、AT所
    Angela Aki 给十五岁的自己
    WCF绑定(Binding)
    几个不错的WCF系列课程
    WCF服务编程学习笔记之服务契约
    asp.net跳转页面的三种方法比较
    Hashtable快速查找的方法
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9186183.html
Copyright © 2011-2022 走看看