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

    题面在这里!

        考虑容斥,我们可以求出用的建筑公司的集合至多是S的方案数(也就是最小生成树中的边只能用集合S内的建筑公司内的),这个跑一下矩阵树定理就好啦(注意可以有重边,因为一条边被不同公司建是算不同的方案的)。

        然后再容斥加加减减算一算就好啦。。。

        (神TM我一开始忘了去掉一行一列答案一直是0 。。。。)

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int ha=1e9+7;
    
    inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
    inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}
    
    inline int ksm(int x,int y){
    	int an=1;
    	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
    	return an;
    }
    
    int n,ci[25],ans,all;
    bool bt[200005];
    
    struct node{
    	int a[21][21];
    	
    	inline void clear(){ memset(a,0,sizeof(a));}
    	
    	node operator +(const node &b)const{
    		node r;
    		for(int i=1;i<=n;i++)
    		    for(int j=1;j<=n;j++) r.a[i][j]=add(a[i][j],b.a[i][j]);
    		return r;
    	}
    	
    	inline int Get(){
    		int an=1;
    		
    		for(int i=1,t,v;i<n;i++){
    			if(!a[i][i]) for(int j=i+1;j<n;j++) if(a[j][i]){
    				for(int k=i;k<n;k++) swap(a[j][k],a[i][k]);
    				an=ha-an; break;
    			}
    			an=an*(ll)a[i][i]%ha;
    			if(!an) break;
    			
    			t=ksm(a[i][i],ha-2);
    			for(int j=i+1;j<n;j++) if(a[j][i]){
    				v=t*(ll)a[j][i]%ha;
    				for(int k=i;k<n;k++) ADD(a[j][k],ha-a[i][k]*(ll)v%ha);
    		    }
    		}
    		
    		return an;
    	}
    }d[21],now;
    
    inline int solve(int S){
    	now.clear();
    	for(int i=1;i<n;i++) if(S&ci[i-1]) now=now+d[i];	
    	return bt[all^S]?ha-now.Get():now.Get();
    }
    
    int main(){
    	ci[0]=1;
    	for(int i=1;i<=20;i++) ci[i]=ci[i-1]<<1;
    	scanf("%d",&n),all=ci[n-1]-1;
    	for(int i=1;i<=all;i++) bt[i]=bt[i^(i&-i)]^1;
    	
    	for(int i=1,m,u,v;i<n;i++){
    		scanf("%d",&m);
    		while(m--){
    			scanf("%d%d",&u,&v);
    			ADD(d[i].a[u][u],1);
    			ADD(d[i].a[v][v],1);
    			ADD(d[i].a[u][v],ha-1);
    			ADD(d[i].a[v][u],ha-1);
    		}
    	}
    	
    	for(int i=1;i<=all;i++) ADD(ans,solve(i));
    	
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    剑指offer——最小的K个数和数组中第K大的元素
    Leetcode刷题指南链接整理
    160. Intersection of Two Linked Lists
    100. Same Tree
    92. Reverse Linked List II
    94. Binary Tree Inorder Traversal
    79. Word Search
    78,90,Subsets,46,47,Permutations,39,40 DFS 大合集
    0x16 Tire之最大的异或对
    0x16 Tire
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9284944.html
Copyright © 2011-2022 走看看