zoukankan      html  css  js  c++  java
  • Solution -「SHOI2016」「洛谷 P4336」黑暗前的幻想乡

    (mathcal{Description})

      link.
      有一个 (n) 个结点的无向图,给定 (n-1) 组边集,求从每组边集选出恰一条边最终构成树的方案树。对 (10^9+7) 取模。
      (2le nle17),边集大小 (0le m_ilefrac{n(n-1)}2)

    (mathcal{Solution})

      (n) 很小,考虑容斥。枚举这 (n-1) 个边集的子集,将子集内的边集的边加入图,用矩阵树定理求出生成树个数,容斥一下就好啦。复杂度 (mathcal O(2^nn^3))

    (mathcal{Code})

    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    
    const int MAXN = 17, MOD = 1e9 + 7;
    int n, m, d[MAXN + 5][MAXN + 5];
    std::vector<std::pair<int, int> > able[MAXN + 5]; 
    
    inline int qkpow ( int a, int b, const int p = MOD ) {
    	int ret = 1;
    	for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = 1ll * ret * ( b & 1 ? a : 1 ) % p;
    	return ret;
    }
    
    inline int det ( int d[MAXN + 5][MAXN + 5] ) {
    	int ret = 1, swp = 1;
    	for ( int i = 1; i < n; ++ i ) {
    		for ( int j = i; j < n; ++ j ) {
    			if ( d[j][i] ) {
    				if ( i ^ j ) std::swap ( d[i], d[j] ), swp *= -1;
    				break;
    			}
    		}
    		if ( ! d[i][i] ) return 0;
    		ret = 1ll * ret * d[i][i] % MOD;
    		int inv = qkpow ( d[i][i], MOD - 2 );
    		for ( int j = i + 1; j < n; ++ j ) {
    			int c = 1ll * inv * d[j][i] % MOD;
    			for ( int k = i; k < n; ++ k ) d[j][k] = ( d[j][k] - 1ll * c * d[i][k] % MOD + MOD ) % MOD;
    		}
    	}
    	return ( ret * swp + MOD ) % MOD;
    }
    
    int main () {
    	scanf ( "%d", &n );
    	for ( int i = 1, m; i < n; ++ i ) {
    		scanf ( "%d", &m );
    		for ( int u, v; m --; ) {
    			scanf ( "%d %d", &u, &v );
    			able[i].push_back ( { u, v } );
    		}
    	}
    	int ans = 0;
    	for ( int s = 1; s < 1 << n >> 1; ++ s ) {
    		int bit = 0; memset ( d, 0, sizeof d );
    		for ( int i = 1; i < n; ++ i ) {
    			if ( ( s >> i - 1 ) & 1 ) {
    				++ bit;
    				for ( int j = 0; j ^ able[i].size (); ++ j ) {
    					int u = able[i][j].first, v = able[i][j].second;
    					++ d[u][u], ++ d[v][v], -- d[u][v], -- d[v][u];
    					if ( d[u][v] < 0 ) d[u][v] += MOD;
    					if ( d[v][u] < 0 ) d[v][u] += MOD;
    				}
    			}
    		}
    		ans = ( ans + ( ( bit & 1 ) ^ ( n & 1 ) ? det ( d ) : -det ( d ) ) ) % MOD;
    	}
    	printf ( "%d
    ", ( ans + MOD ) % MOD );
    	return 0;
    }
    
  • 相关阅读:
    HDU2586 How far away?(tarjan的LCA)
    You Raise Me Up
    POJ2891 Strange Way to Express Integers(中国剩余定理)
    POJ2142 The Balance(扩展欧几里得)
    HDU 1166模仿大牛写的线段树
    NetWord Dinic
    HDU 1754 线段树裸题
    hdu1394 Minimum Inversion Number
    hdu2795 Billboard
    【完全版】线段树
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13224105.html
Copyright © 2011-2022 走看看