首页 > 其他分享 >「JSOI2008」最小生成树计数 题解报告

「JSOI2008」最小生成树计数 题解报告

时间:2023-08-08 12:12:31浏览次数:49  
标签:题解 ll JSOI2008 最小 生成 计数 质数 边权

简要题意

现在给出了一个简单无向加权图。你希望知道这个图中有多少个不同的最小生成树。(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的)。输出方案数对\(31011\)取模。

SOLUTION

这个题求最小生成树的方案

所以我们从最小生成树入手

(根据kruskal的思路)

我们可以知道 同一个图的每个最小生成树中,边权相等的边数量相等。

感性理解:然后由于要求的是最小生成树的方案

所以对于树边,我们只能用同样权值去替代ta

否则就不是最小生成树的值

我们考虑枚举边权

每次根据剩下树边缩点(其实就是将点连上了,方便处理)

得到一张新的DAG,

我们只是要考虑边权相等的边对于新图生成树的方案数

因此我们可以做矩阵树

最后的答案就是所有的乘积

注意:

这个题模数P不是质数

因此不能用逆元求det值

CODE

const int N=1e2+2,M=1e3+2,P=31011;//不是质数 
struct node{ll x,y,w;}t[M],s[M];
vector<node> G[M]; 
bool operator<(node a,node b){
    return a.w<b.w;
}
ll is[M],fa[N],c[N],n,D[N][N],A[N][N],C[N][N]; 
ll find(ll x){
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1)res=res*a%P;
        a=a*a%P; 
		b>>=1;
    }
    return res%P;
}
ll det(ll n){
	ll ans=1;
	for(ll i=1;i<n;i++){
		for(ll j=i+1;j<=n;j++){ 
			while(C[j][i]){ 
				ll l=C[i][i]/C[j][i];//l表示辗转相减的次数
				for(ll k=1;k<=n;k++){
					C[i][k]=(C[i][k]-C[j][k]*l%P+P)%P; 
				} 
			 	for(ll k=1;k<=n;k++){
			 		swap(C[i][k],C[j][k]);
			 	}//交换两列位置取相反数
			 	ans*=-1;//相反数
		 	}
		}
	}
	for(ll i=1;i<=n;i++){
		ans=(ans*C[i][i]%P+P)%P;
	}//此时已经削减为上三角矩阵,所以直接求对角线元素之积就可以了
	return ans;
}
int main(){
    ll n,m,all=0,tmp=0,cnt=0;
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++) fa[i]=i;
    for(ll i=1;i<=m;i++){
    	scanf("%lld%lld%lld",&t[i].x,&t[i].y,&t[i].w);
    }
    sort(t+1,t+m+1);
    //kruskal 
    for(ll i=1;i<=m;i++){
    	ll x=t[i].x,y=t[i].y,w=t[i].w;
        if(w!=tmp) all++,tmp=w;
        G[all].push_back(t[i]);
        if(find(x)==find(y))continue;
        fa[find(x)]=find(y);
        is[all]=1;
		s[++cnt]=t[i];
		s[cnt].w=all;
    }
    if(cnt!=n-1){
        printf("0");
        return 0;
    } 
    ll ans=1;
    for(ll i=1;i<=all;i++){
        if(!is[i]) continue;//如果最小生成树中没有用到此边权 
		for(ll i=1;i<=n;i++) fa[i]=i;
		ll tot=0;
		for(ll j=1;j<=cnt;j++){		//将生成树上的边全部连上并缩点
			ll x=s[j].x,y=s[j].y,w=s[j].w;
			if(w==i) continue;
			if(find(x)==find(y))continue;
			fa[find(x)]=find(y);
		}
		for(ll j=1;j<=n;j++){
			if(fa[j]==j) c[j]=++tot;
		}
		for(ll j=1;j<=n;j++){
			c[j]=c[find(j)];
		}
        for(auto j:G[i]){//将原图中此边权的边全部连上 
            ll x=c[j.x],y=c[j.y];
            D[x][x]++,D[y][y]++;
            A[x][y]++,A[y][x]++;
        }
        for(ll j=1;j<=tot;j++){
        	for(ll k=1;k<=tot;k++){
        		C[j][k]=(D[j][k]-A[j][k]+P)%P;
        	}
        }
        ans=ans*det(tot-1)%P;
        for(auto j:G[i]){ //删除连上的边 
            ll x=c[j.x],y=c[j.y];
            D[x][x]--,D[y][y]--;
            A[x][y]--,A[y][x]--;
        }
    }
    printf("%lld",ans);
    return 0;
}

完结撒花❀

标签:题解,ll,JSOI2008,最小,生成,计数,质数,边权
From: https://www.cnblogs.com/yvette1217/p/17613822.html

相关文章

  • 题解 [国家集训队] 稳定婚姻
    题目链接首先我们考虑用图论的边描述这个关系。若两者存在夫妻或情侣关系,就连一条边(是有向边还是无向边呢?)。先来考虑两对夫妻的情况,若夫妻边与情侣边交替出现。且一对夫妻在同一个环内,则可以说明分开后能够重新找到另一半。如下图:夫妻a-男b-女c-男d-女情侣a-男d-女c-......
  • 洛谷 CF572B题解
    思路首先,将SELL和BUY交易数据分别存放在两个桶。接下来,从小到大遍历。取出最小的\(s\)个:从大到小遍历,取出最大的\(s\)个。分别存放在queue和stack中,如果不到\(s\)就取完为止。最后,输出queue和stack中的所有元素即可。代码实现:#include<bits/stdc++.h>usi......
  • 题解 [POI2005] SZA-Template
    题目链接充分暴露出对\(border\)结合\(dp\)理解的不足。先来推结论,一个字符串的印章一定是其\(border\),因为只有这样才可能兼顾首尾,但是他的\(border\)不一定是其印章,两个条件不能互推。设\(dp_i\)表示前\(i\)个字符串的最小印章长度。现在考虑如何转移。\(dp_i\)......
  • BZOJ3337 ORZJRY I 题解
    https://vjudge.net/problem/黑暗爆炸-3337题意试维护一个序列,支持以下\(11\)种操作:输入格式说明1xw在\(a_x\)后插入\(w\)2x删除\(a_x\)3xy翻转\((a_x,a_{x+1},\dots,a_y)\)4xyk将\((a_x,a_{x+1},\dots,a_y)\)右移\(k\)次......
  • CF671D Roads in Yusland 题解
    题目链接题目要求我们求出选出若干条路径并最小化花费,如果这是在链上,我们可以考虑直接枚举每条路径的右端点dp,那树呢?把路径剖分整个覆盖的集合就不一定连续了,没法dp,况且题目里给了很强的条件:路径一定是从孩子到祖先,硬转链用不上这个性质,貌似不太对。上述思考启发我们利用树的......
  • “科大国创杯”2023 年安徽省青少年信息学科普日活动 简要题解
    “科大国创杯”2023年安徽省青少年信息学科普日活动简要题解小学组T1grade直接累加即可。不需要按百分比算(也就是别/100),那样可能会出现一些浮点数误差。T2order暴力枚举t就可以了T3string答案即为cnt4+cnt5-cnt20。注意到对于一个数,我们只关心其个位和十位就......
  • 打开电脑中应用程序及问题解决方案
    1、使用os.system()函数:示例代码importosos.system("notepad.exe")这将在Windows系统上打开记事本应用程序。2、使用subprocess示例代码:importsubprocesssubprocess.Popen(['notepad.exe'])3、使用webbrowser示例代码:importwebbrowserwebbrowser.open('http://www.goog......
  • 【题解】 Pattern Matching in A Minor "Low Space" CCPC Mianyang 2022
    https://vjudge.net/contest/573644#problem/K字符串匹配,但卡空间。考虑哈希做法,不妨把\(s\)每\(20000\)个字符哈希成一个字符,于是\(s\)长度只有\(500\),可以跑个KMP。于是对于\(t\),我们只需要同时维护\(20000\)个KMP的指针。但如果字符串长度不是\(20000\)的倍......
  • P9498 「RiOI-2」equals题解
    题目传送门:P9498「RiOI-2」equals-洛谷|计算机科学教育新生态(luogu.com.cn)这是洛谷月赛Div.2T3,由于我比较菜,只能赛场上切到T3(T4是黑。),开题我们很容易就看出这道题首先需要初始化每个点到根节点的最短路,而且边权都为1,所以我们先无脑打一个堆优化的dijkstra,剩下的就是处......
  • P1005 [NOIP2007 提高组] 矩阵取数游戏题解
    题面传送门:P1005[NOIP2007提高组]矩阵取数游戏-洛谷|计算机科学教育新生态(luogu.com.cn)分析题目可知,这道题是一道求最值的问题,第一次看题没有认真读题,以为是每次只在某一行中选一个数,于是想了半天无果。重新读题才发现每次需要每行都取,那么这就很简单了,相当于在每一行......