P11394 题解
DaiRuiChen007 · · 题解
Problem Link
题目大意
给定
n\times m 网格,以及长度为k 的字符串S (字符集东南西北),初始每个格子为白色。在第
t 个时刻,我们选取方向S^{\infty}_t ,然后取出每个格子在该方向的邻居,如果某个格子(i,j) 连续a_{i,j} 个时刻都取到了一个黑色的邻居,那么这个格子也染黑。你要选择一个格子染黑,最小化充分大时间后的黑色格子数量,并且求出有多少个取到最小值的起点。
数据范围:
n,m\le 800,k\le 10^5 。
思路分析
首先我们要快速判定一个格子是否能染黑,取出其所有黑色邻居所在的方向,记为集合
对每个
那么暴力就是从每个点开始 bfs,但显然无法通过。
考虑利用一些已有的信息,例如从
因此可以考虑连边
先对这张图缩点,那么答案只可能是无出度的强连通分量。
可以发现如果存在一条边
因此我们取出这张图的一个内向生成森林,则答案一定来自每个根所在的强连通分量。
如果求出极大的一个内向生成森林,显然一个强连通分量内不会有两个根,因此对每个根暴力 bfs 复杂度正确。
那么问题就变成了在这张图上求出一个极大内向生成森林。
稠密图上的生成树问题可以考虑 Boruvka,在这题中,我们动态维护一个内向生成森林,然后对每个根找一条连向其他树的出边,然后以任意顺序加入这条边(只要不成环)。
很显然每轮增广后连通块数量减半,那么增广轮数是
每轮增广就从每个根开始 bfs,如果遇到一个和自己不同色的点就立即退出,那么每个点只会被同色的根 bfs 到,复杂度
时间复杂度
代码呈现
#include<bits/stdc++.h>
using namespace std;
const int MAXN=805,MAXL=2e5+5,MAXV=1e6+5,inf=1e9,dx[]={-1,1,0,0},dy[]={0,0,-1,1};
char op[MAXL];
int n,m,q,lim[16],a[MAXN][MAXN];
int cl[MAXN][MAXN],id[MAXN][MAXN],dsu[MAXV],tot;
bool vis[MAXN][MAXN];
int ty(char c) { return c=='N'?0:(c=='S'?1:(c=='W'?2:3)); }
int find(int x) { return dsu[x]^x?dsu[x]=find(dsu[x]):x; }
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>q>>n>>m;
for(int i=1;i<=q;++i) cin>>op[i],op[i+q]=op[i];
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) cin>>a[i][j],id[i][j]=++tot;
for(int s=1;s<16;++s) {
for(int i=1,j=lim[s]=-1;i<=2*q;++i) if(!(s>>ty(op[i])&1)) {
if(~j) lim[s]=max(lim[s],i-j-1); j=i;
}
if(lim[s]==-1) lim[s]=inf;
}
iota(dsu+1,dsu+tot+1,1);
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(a[i][j]) cl[i][j]=id[i][j];
while(true) {
memset(vis,false,sizeof(vis));
vector <array<int,2>> E;
int ans=inf,cnt=0;
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(cl[i][j]==id[i][j]) {
int z=0; queue <array<int,2>> Q;
Q.push({i,j}),vis[i][j]=true;
auto is=[&](int x,int y){ return vis[x][y]&&cl[x][y]==cl[i][j]; };
while(Q.size()) {
int u=Q.front()[0],v=Q.front()[1]; Q.pop(),++z;
for(int d:{0,1,2,3}) {
int x=u+dx[d],y=v+dy[d];
if(!a[x][y]||is(x,y)) continue;
int s=is(x-1,y)|is(x+1,y)<<1|is(x,y-1)<<2|is(x,y+1)<<3;
if(a[x][y]<=lim[s]) {
if(cl[x][y]==cl[i][j]) Q.push({x,y}),vis[x][y]=true;
else { E.push_back({cl[i][j],cl[x][y]}); goto _; }
}
}
}
if(ans>z) ans=cnt=z;
else if(ans==z) cnt+=z;
_:;
}
if(E.empty()) return cout<<ans<<"\n"<<cnt<<"\n",0;
for(auto e:E) if(find(e[1])!=e[0]) dsu[e[0]]=find(e[1]);
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(a[i][j]) cl[i][j]=find(id[i][j]);
}
return 0;
}