zoukankan      html  css  js  c++  java
  • [JSOI2008]最小生成树计数

    传送门

    Description

    最小生成树计数

    Solution 

    首先,考虑kruskal的过程,发现相同权值的边的集合对生成树的贡献是一样的

    所以对权值排序按照从小到大的顺序

    分别根据(Matrix-tree)做生成树计数

    每个权值处理完,都缩点一下

    为了好写,可以把很多联通块连在一起做

    Code 

    /*最小生成树计数 */ 
    #include<bits/stdc++.h>
    #define ll long long
    #define dbg1(x) cerr<<#x<<"="<<(x)<<" "
    #define dbg2(x) cerr<<#x<<"="<<(x)<<"
    "
    #define dbg3(x) cerr<<#x<<"
    "
    using namespace std;
    #define reg register
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    const int P=919260817,MN=305,ME=1e5+5;
    int K[MN][MN];
    int Mul(int x,int y){return (1ll*x*y)%P;}
    int Add(int x,int y){return (x+y)%P;}
    int Dec(int x,int y){return Add(x,P-y);}
    int MatT(int &n)
    {
    	int r=1,t;reg int i,j,k;
    	for(i=1;i<n;++i)
    	{
    		for(j=i+1;j<n;++j)while(K[j][i])
    		{
    			t=K[i][i]/K[j][i];
    			if(t)for(k=i;k<n;++k)
    			K[i][k]=Dec(K[i][k],Mul(K[j][k],t));
    			swap(K[i],K[j]);r=Dec(0,r);
    		}
    		r=Mul(r,K[i][i]);if(!r) return r;
    	}
    	return r;
    }
    int N,M,fa[MN],re[MN],tt,st[MN],ans,ff[MN];
    int getf(int *f,int x){return f[x]==x?x:f[x]=getf(f,f[x]);}
    void union_(int *f,int x,int y){x=getf(f,x);y=getf(f,y);if(x!=y)f[y]=x;}
    struct edge{int x,y,w;}e[ME];
    bool cmp(edge x,edge y){return x.w<y.w;}
    vector<int>G[MN];
    void ins(int x,int y){++K[x][x],++K[y][y],K[x][y]=Dec(K[x][y],1),K[y][x]=Dec(K[y][x],1);}
    int main()
    {
    	freopen("crazy.in","r",stdin);
    	freopen("crazy.out","w",stdout);
    	N=read(),M=read();
    	reg int l,r,i,j,x,y;
    	for(i=1;i<=N;++i)fa[i]=ff[i]=i;
    	for(i=1;i<=M;++i)e[i].x=read(),e[i].y=read(),e[i].w=read();
    	std::sort(e+1,e+M+1,cmp);
    	for(ans=l=1,r=0;l<=M;++l)
    	{
    		while(e[r+1].w==e[l].w)++r;
    		for(tt=0,i=l;i<=r;++i)
    		{
    			x=getf(fa,e[i].x);y=getf(fa,e[i].y);if(x==y)continue;
    			if(!re[x])re[x]=++tt,st[tt]=x;x=re[x];
    			if(!re[y])re[y]=++tt,st[tt]=y;y=re[y];
    			ins(x,y);union_(ff,x,y);
    		}
    		if(!tt)continue;
    		for(j=getf(ff,1),i=1;i<=tt;++i)if(getf(ff,i)==i&&ff[i]!=j)ins(j,i);
    		ans=Mul(ans,MatT(tt));
    		for(i=1;i<=tt;++i)re[st[i]]=0;
    		for(i=1;i<=tt;++i)ff[i]=i;
    		for(i=1;i<=tt;++i)for(j=1;j<=tt;++j)K[i][j]=0;
    		for(i=l;i<=r;++i)union_(fa,e[i].x,e[i].y);l=r;
    	}
    	for(i=1,j=0;i<=N;++i)j+=i==getf(fa,i);
    	if(j>1)printf("0
    ");else printf("%d
    ",ans);
    	return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    微信公众平台接口获取时间戳为10位,java开发需转为13位
    redis实现哨兵机制
    redis配置主从复制
    C 语言字符 和字符串输出
    C 小写字母编程大写并输出
    C语言计算机器运行时间
    C 猜数游戏
    C 产生随机码 (输入数字来产生)
    C 产生随机码
    C 语言链表操作例程 (待完善)
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/11777641.html
Copyright © 2011-2022 走看看