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

    题目

    这题好熟练啊

    看到恰好想容斥这非常熟练吧

    又发现数据范围这么小,显然是允许我们(2^n)暴力容斥的

    于是我们枚举一个二进制状态(S),我们只使用包含在(S)这个状态里的公司的边,我们这样求出的就是至少有(n-|S|)个公司没有修建的方案数,容斥系数显然是((-1)^{n-|S|})

    至于这个方案数怎么计算,交给矩阵树定理就好啦

    复杂度(O(2^nn^3))

    代码

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=18;
    const int mod=1e9+7;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n,cnt[131078],num[maxn],N;
    int a[maxn][maxn];
    std::vector<int> x[maxn],y[maxn];
    inline int ksm(int a,int b) {
    	int S=1;
    	while(b) {if(b&1) S=(1ll*S*a)%mod;b>>=1;a=(1ll*a*a)%mod;}
    	return S;
    }
    inline int qm(int a) {return a>=mod?a-mod:a;}
    inline int solve(int S) {
    	for(re int i=1;i<n;i++)
    		for(re int j=1;j<n;j++)
    			a[i][j]=0;
    	for(re int i=1;i<n;i++) {
    		if(!(S&(1<<(i-1)))) continue;
    		for(re int j=1;j<=num[i];j++) {
    			int u=x[i][j-1],v=y[i][j-1];
    			a[u][u]++,a[v][v]++;
    			a[u][v]--,a[v][u]--;
    		}
    	}
    	for(re int i=1;i<n;i++)
    		for(re int j=1;j<n;j++) 
    			if(a[i][j]<0) a[i][j]+=mod;
    	int o=(cnt[S^N]&1),ans=1;
    	for(re int i=1;i<n;i++) {
    		int p;
    		for(p=i;p<n;++p) if(a[p][i]) break;
    		if(p==n) return 0;
    		if(i!=p) std::swap(a[p],a[i]),o^=1;
    		int Inv=ksm(a[i][i],mod-2);
    		for(re int j=i+1;j<n;j++) {
    			int t=(1ll*Inv*a[j][i])%mod;
    			for(re int k=i;k<n;k++)
    				a[j][k]=qm(a[j][k]-1ll*a[i][k]*t%mod+mod);
    		}
    	}
    	for(re int i=1;i<n;i++)
    		ans=(1ll*ans*a[i][i])%mod;
    	if(o) return qm(mod-ans);
    	return ans;
    }
    int main() {
    	n=read();N=(1<<(n-1))-1;
    	for(re int i=1;i<=N;i++) cnt[i]=cnt[i>>1]+(i&1);
    	for(re int i=1;i<n;i++) {
    		num[i]=read();
    		for(re int j=1;j<=num[i];j++)
    			x[i].push_back(read()),y[i].push_back(read());
    	}
    	int tot=0;
    	for(re int i=0;i<=N;i++)
    		tot=qm(tot+solve(i));
    	printf("%d
    ",tot);
    	return 0;
    }
    
  • 相关阅读:
    10个强大的Apache开源模块
    Flume日志收集(转载)
    hbase安装配置(整合到hadoop)
    Hadoop与HBase兼容版本汇总
    关于Mysql Proxy LUA实现Mysql读写分离
    Redis发布了集群版3.0.0 beta
    Spring MVC 学习之 400 错误
    Mahout安装(Hadoop 1.2.1 版本)
    【Android】性能优化
    【Android】asynchronous http client
  • 原文地址:https://www.cnblogs.com/asuldb/p/10723148.html
Copyright © 2011-2022 走看看