zoukankan      html  css  js  c++  java
  • 【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理

    题目描述

    给出 $n$ 个点和 $n-1$ 种颜色,每种颜色有若干条边。求这张图多少棵每种颜色的边都出现过的生成树,答案对 $10^9+7$ 取模。

    输入

    第一行包含一个正整数 N(N<=17), 表示城市个数。
    接下来 N-1 行,其中第 i行表示第 i个建筑公司可以修建的路的列表:
    以一个非负数mi 开头,表示其可以修建 mi 条路,接下来有mi 对数,
    每对数表示一条边的两个端点。其中不会出现重复的边,也不会出现自环。

    输出

    仅一行一个整数,表示所有可能的方案数对 10^9 + 7 取模的结果。

    样例输入

    4
    2 3 2 4 2
    5 2 1 3 1 3 2 4 1 4 3
    4 2 1 3 2 4 1 4 2

    样例输出

    17


    题解

    容斥原理+矩阵树定理

    答案为:随便选的 - 钦定1种颜色不能选的 + 钦定2种颜色不能选的 - ... 。

    爆搜每种颜色是否被钦定不能选,然后使用矩阵树定理求出当前条件下的生成树个数即可。

    时间复杂度 $O(2^n·n^3)$ 。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define mod 1000000007
    typedef long long ll;
    using namespace std;
    int n , m[18] , vx[18][140] , vy[18][140] , v[18];
    ll a[18][18] , ans;
    inline ll pow(ll x , int y)
    {
    	ll ans = 1;
    	while(y)
    	{
    		if(y & 1) ans = ans * x % mod;
    		x = x * x % mod , y >>= 1;
    	}
    	return ans;
    }
    void dfs(int x , int flag)
    {
    	if(x == n)
    	{
    		memset(a , 0 , sizeof(a));
    		int i , j , k;
    		ll now = 1 , t;
    		for(i = 1 ; i < n ; i ++ )
    			if(v[i])
    				for(j = 1 ; j <= m[i] ; j ++ )
    					a[vx[i][j]][vx[i][j]] ++ , a[vy[i][j]][vy[i][j]] ++ , a[vx[i][j]][vy[i][j]] -- , a[vy[i][j]][vx[i][j]] -- ;
    		for(i = 2 ; i <= n ; i ++ )
    		{
    			for(j = i ; j <= n ; j ++ )
    				if(a[j][i])
    					break;
    			if(j > n) break;
    			if(j != i)
    			{
    				flag = -flag;
    				for(k = i ; k <= n ; k ++ )
    					swap(a[i][k] , a[j][k]);
    			}
    			now = now * a[i][i] % mod , t = pow(a[i][i] , mod - 2);
    			for(j = i ; j <= n ; j ++ ) a[i][j] = a[i][j] * t % mod;
    			for(j = i + 1 ; j <= n ; j ++ )
    				for(t = a[j][i] , k = i ; k <= n ; k ++ )
    					a[j][k] = (a[j][k] - t * a[i][k] % mod + mod) % mod;
    		}
    		if(i > n) ans = (ans + flag * now + mod) % mod;
    		return;
    	}
    	v[x] = 1 , dfs(x + 1 , flag);
    	v[x] = 0 , dfs(x + 1 , -flag);
    }
    int main()
    {
    	int i , j;
    	scanf("%d" , &n);
    	for(i = 1 ; i < n ; i ++ )
    	{
    		scanf("%d" , &m[i]);
    		for(j = 1 ; j <= m[i] ; j ++ )
    			scanf("%d%d" , &vx[i][j] , &vy[i][j]);
    	}
    	dfs(1 , 1);
    	printf("%lld
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    UnityGUI Keynote
    Unity3D Asset 导入&导出
    Unity3d平台信息设置
    Unity3D自带Demo AngryBots路径
    如何判定Unity已破解成功
    fbx模型
    Init & Deinit & ARC
    Subscript & Inheritance
    Properties & Method
    Enumeration & Class & Structure
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8716038.html
Copyright © 2011-2022 走看看