AT_abc334_g [ABC334G] Christmas Color Grid 2 题解

对于这个网格图四联通建边,然后建圆方树。

很显然一个图中删掉一个点增加的连通块数量为圆方树上这个点的度数 1-1

于是直接就做完了。每个点累加答案,求个平均数就好了。

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 1005, MOD = 998244353, HSMOD = 1610612741, HSMOD2 = 998244353; // Remember to change

int n, m, q, t, a[N];
char c[N][N];

namespace FastIo
{
	#define QUICKCIN ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
	int read()
	{
		char ch = getchar();
		int x = 0, f = 1;
		while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
		while (ch == '-')
		{
			f = -f;
			ch = getchar();
		}
		while (ch >= '0' && ch <= '9')
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
			ch = getchar();
		}
		return x * f;
	}
	template<class T>
	void write(T x)
	{
		if (x < 0)
		{
			putchar('-');
			x = -x;
		}
		if (x > 9) write(x / 10);
		putchar(x % 10 + '0');
	}
	template<class T>
	void writeln(T x)
	{
		write(x);
		putchar('\n');
	}
}

int qpow(int a, int b)
{
	int res=1LL,base=a;
	while(b)
	{
		if(b&1LL)
		{
			res=res*base%MOD;
		}
		base=base*base%MOD;
		b>>=1LL;
	}
	return res;
}

int get(int x, int y)
{
	return (x-1)*m+y;
}

class Union_Find
{
public:
	int fa[N*N],sz[N*N];
	void Init()
	{
		for(int i=1;i<N*N;i++) fa[i]=i,sz[i]=1;
	}
	int find(int u)
	{
		return (fa[u]==u?u:find(fa[u])); 
	}
	pair<int, int> merge(int u, int v)
	{
		if((u=find(u))==(v=find(v))) return make_pair(-1,-1);
		if(sz[u]<sz[v]) swap(u,v);
		sz[u]+=sz[v];
		fa[v]=u;
		return make_pair(u,v);
	}
	void del(int u, int v)
	{
		sz[u]-=sz[v];
		fa[v]=v;
	}
}uf;

bool vis[N][N];
int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};

void dfs(int x, int y)
{
	vis[x][y]=1;
	for(int i=0;i<4;i++)
	{
		int nx=x+dx[i],ny=y+dy[i];
		if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&!vis[nx][ny]&&c[nx][ny]=='#')
		{
			dfs(nx,ny);
			uf.merge(get(x,y),get(nx,ny));
		}
	}
}

int dfn[5*N*N],low[5*N*N];
vector<int> NG[5*N*N];
int idx;
int stk[5*N*N],top;
vector<int> G[5*N*N];
int CC;

void tarjan(int u)
{
	dfn[u]=low[u]=++idx;
	stk[++top]=u;
	for(auto&j:G[u])
	{
		if(!dfn[j])
		{
			tarjan(j);
			low[u]=min(low[u],low[j]);
			if(low[j]==dfn[u])
			{
				CC++;
				for(int y=0;y^j;top--)
				{
					y=stk[top];
					NG[CC].emplace_back(y);
					NG[y].emplace_back(CC);
				}
				NG[u].emplace_back(CC);
				NG[CC].emplace_back(u);
			}
		}
		else low[u]=min(low[u],dfn[j]);
	}
}

signed main()
{
	ios::sync_with_stdio(0), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> m;
	CC=n*m;
	uf.Init();
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>c[i][j];
			cnt+=(c[i][j]=='#');
		}
	}
	int cc=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			for(int k=0;k<4;k++)
			{
				int ni=i+dx[k],nj=j+dy[k];
				if(ni>=1&&ni<=n&&nj>=1&&nj<=m&&c[i][j]=='#'&&c[ni][nj]=='#')
				{
					G[get(i,j)].emplace_back(get(ni,nj));
				}
			}
			if(c[i][j]=='#'&&!vis[i][j]) 
			{
				dfs(i,j),cc++;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(c[i][j]=='#')
			{
				if(!dfn[get(i,j)])
				{
					top=0;
					tarjan(get(i,j));
				}
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(c[i][j]=='#')
			{
				if(!dfn[get(i,j)])
				{
					top=0;
					tarjan(get(i,j));
				}
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(c[i][j]=='#')
			{
				int nc=cc+NG[get(i,j)].size()-1;
				ans=(ans+nc*qpow(cnt,MOD-2LL)%MOD)%MOD; 
			}
		}
	}
	cout<<ans<<"\n";
	return 0;
}
posted @   HappyBobb  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示