AT_abc334_g [ABC334G] Christmas Color Grid 2 题解
对于这个网格图四联通建边,然后建圆方树。
很显然一个图中删掉一个点增加的连通块数量为圆方树上这个点的度数
于是直接就做完了。每个点累加答案,求个平均数就好了。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现