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

    传送门

    首先这题要用到矩阵树,简单来说的话就是一个无向图的生成树个数可以按如下方法计算。设图(G)的邻接矩阵为(A),度数矩阵为(D),其中邻接矩阵的第(i)行第(j)列表示(i)(j)之间有多少条边(允许重边),度数矩阵的第(i)行第(i)列表示(i)的度数且除对角线外所有元素均为(0)。那么这个无向图的基尔霍夫矩阵(K=D-A)(K)的任意一个主子式(即去掉第(i)行第(i)列后剩下的矩阵的行列式)的绝对值即为该无向图的生成树

    矩阵的行列式的话……直接用高斯消元把它消成上三角矩阵,记录一下行的交换次数表示正负即可

    然后本题明显要用到容斥,(ans=)刚好有(n-1)个公司的方案(-)刚好有(n-2)个公司的方案(+...)

    暴力枚举即可

    //minamoto
    #include<bits/stdc++.h>
    #define ll long long
    #define rint register int
    using namespace std;
    #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    char buf[1<<21],*p1=buf,*p2=buf;
    int read(){
        int res,f=1;char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    const int N=21,P=1e9+7;
    inline int add(int x,int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(int x,int y){return x-y<0?x-y+P:x-y;}
    inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=1ll*a*a%P)if(b&1)res=1ll*res*a%P;return res;}
    int n,m,u,v,tot,ans,head[N],a[N][N],G[N][N];struct eg{int nx,u,v;}e[8005];
    int det(int n){
    	int ans=1,f=1,t,inv,mx;
    	for(rint i=1;i<=n;++i)for(rint j=1;j<=n;++j)G[i][j]=add(a[i][j],P);
    	for(rint i=1;i<=n;++i){
    		mx=i;
    		for(rint j=i;j<=n;++j)if(G[j][i]>G[mx][i])mx=j;
    		if(mx!=i){for(rint k=i;k<=n;++k)swap(G[i][k],G[mx][k]);f=-f;}
    		inv=ksm(G[i][i],P-2);
    		for(rint j=i+1;j<=n;++j)if(G[j][i]){
    			t=1ll*G[j][i]*inv%P;
    			for(rint k=i;k<=n;++k)G[j][k]=dec(G[j][k],1ll*G[i][k]*t%P);
    		}ans=1ll*ans*G[i][i]%P;
    	}
    	return add(P,f*ans);
    }
    void dfs(int x,int y){
    //	printf("%d
    ",ans);
    	if(x==n)return (void)(ans=y&1?dec(ans,det(n-1)):add(ans,det(n-1)));
        dfs(x+1,y);
    	for(rint i=head[x];i;i=e[i].nx){
    		u=e[i].u,v=e[i].v;
    		--a[u][u],--a[v][v],++a[u][v],++a[v][u];
    	}
    	dfs(x+1,y+1);
    	for(rint i=head[x];i;i=e[i].nx){
    		u=e[i].u,v=e[i].v;
    		++a[u][u],++a[v][v],--a[u][v],--a[v][u];
    	}
    }
    inline void add_edge(int i,int u,int v){e[++tot]={head[i],u,v},head[i]=tot;}
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read();
    	for(rint i=1;i<n;++i){
    		m=read();
    		for(rint j=1;j<=m;++j)u=read(),v=read(),add_edge(i,u,v),++a[u][u],++a[v][v],--a[u][v],--a[v][u];
    	}
    	dfs(1,0);printf("%d
    ",ans);return 0;
    }
    
  • 相关阅读:
    【代码笔记】iOS-点击搜索跳转到另外一个页面
    【代码笔记】iOS-仿安卓,本页出现多个选择项
    【代码笔记】iOS-点击任何处,显示出红色的UIView
    【代码笔记】iOS-点击任何处,出现城市
    【代码笔记】iOS-点击加号增加书架,点击减号减少书架
    【代码笔记】iOS-点击出现选择框
    【代码笔记】iOS-底下滚动,上面标题栏也会跟着变动
    【代码笔记】iOS-等待动画
    【代码笔记】iOS-登陆单例
    【代码笔记】iOS-获得现在的时间
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9979476.html
Copyright © 2011-2022 走看看