Codeforces Round #706 (Div. 2)

E. Garden of the Sun

题目描述

给定一个包含X.\(n\times m\) 的矩阵,你需要把X改成.使得所有X向四周连边之后构成一棵树。

初始时X两两没有公共点。

\(1\leq n,m\leq 500\)

解法

每空两行把.全部染成X,这时候没有环,但也不连通。

空出来的这两行挑一个连起来。

最后特判一下最下面的情况,因为初始时X之间没有公共边所以不会形成环。

F. BFS Trees

题目描述

点此看题

\(n\) 个点 \(m\) 条边的有向图,定义一棵生成树扎根在 \(u\) 当且仅当 \(u\) 到所有节点的最短路都是树上路径长度,对所有 \((u,v)\) 求出有多少生成树同时扎根在 \(u,v\)

\(n\leq 400,m\leq 600\)

解法

不妨考虑一个简单的情况,怎么求生成树扎根在 \(u\) 的方案数?

可以求出 \(u\)\(\tt bfs\) 树,这样就满足 \(u\) 到所有点的最短路就是树上路径长度,那么考虑把这棵树替换成别的样子,显然对于某个点可以修改他连上去的边,设它连到上一级的边数是 \(cnt(u)\),那么 \(\prod cnt(i)\) 就是答案。

再扩展到本题的情况,是可以用类似的方法的,只是我们把 \(\tt bfs\) 树以 \(u,v\) 建出来好像都不太合适,考虑 \((u,v)\) 最短路径上的点是一定会出现的(如果最短路有多条那么答案是 \(0\)),那么把 \(\tt bfs\) 树以这个最短路为"根"建出来,对于其他的点选到 \(u,v\) 同时都是最短路的边即可,然后用乘法原理。

时间复杂度 \(O(n^3)\)

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
const int M = 505;
const int MOD = 998244353;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,f[M][M];vector<int> g[M];
signed main()
{
	n=read();m=read();
	memset(f,0x3f,sizeof f);
	for(int i=1;i<=n;i++) f[i][i]=0;
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		g[u].push_back(v);
		g[v].push_back(u);
		f[u][v]=f[v][u]=1;
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
	for(int i=1;i<=n;i++,puts(""))
		for(int j=1;j<=n;j++)
		{
			int ans=1,t=0;
			for(int k=1;k<=n;k++)
				if(f[i][k]+f[k][j]==f[i][j])
					t++;
			if(t>f[i][j]+1) ans=0;
			for(int k=1;k<=n;k++)
				if(f[i][k]+f[k][j]!=f[i][j])
				{
					int cnt=0;
					for(int v:g[k])
						cnt+=(f[i][v]+1==f[i][k]
						&& f[j][v]+1==f[j][k]);
					ans=1ll*ans*cnt%MOD;
				}
			printf("%d ",ans);
		}
}
posted @ 2021-05-27 16:47  C202044zxy  阅读(56)  评论(0编辑  收藏  举报