1 条题解
-
0
我会做,好耶。
首先可以发现风向串并不重要,我们可以预处理出 表示所有风向都在集合 内的最长连续段,接下来很容易就可以判断一个点是否会被周围的点传染。
先不管计数。
容易证明只要从点 开始搜索可以传染到 ,那么选择 作为起点就一定不劣于 。此时,我们从 往 连一条边,表示我们不需要求 的答案,求 就可以了。随着我们的搜索,整张图会形成一个森林。
我们考虑每次从没有出度的点开始搜索以他为起点的传染情况,如果传染到了一个和自己不在同一个连通块里的点,那就可以直接连边(和指向的连通块合并)然后扔掉当前点。如果在同一个连通块里则要继续搜索,因为显然你再扔掉当前点就成环了,当前连通块内所有点都有出度,但你没算出答案。
如果传染到最后都没能走出自己这个连通块,那么我们就算出了这个连通块的答案,算进总答案里,之后直接不考虑这个块即可。因为如果别的块指向这个块内的点,那个块整体都不优。
假如我们从一个大小为 的连通块开始搜索,在至多传染 个位置之后,就要么传染不动,要么传染到了别的连通块并与之合并了,进行一次这样的搜索的时间复杂度是 。在进行足够多搜索之后,所有的连通块全都被删掉,也就被统计进答案里了。
容易想到,如果我们每次从最小的连通块开始搜索,就可以保证每次合并都是小集合向大集合合并,时间复杂度是小集合的大小。这是启发式合并的过程,时间复杂度为 。
然后考虑计数。我们只在传染不动的时候会统计答案,此时,因为我们是从一个连通块的根开始搜索,他能走到的所有点也都能走到他自己,换言之,他走到的点之间的可达关系构成一个 SCC。 显然一个点的可达点数在当前连通块内最小当且仅当他在这个 SCC 里面。所以这个连通块的可行点数数值上就是最小答案。
代码:
#include<bits/stdc++.h> using namespace std; int M,n,m; #define N 805 char s[200005],t[10]="NSWE"; int fs[16]; inline int id(int x,int y){ return (x-1)*m+y; } int fa[N*N],sz[N*N],a[N][N],vis[N][N],dead[N][N]; int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } priority_queue<pair<int,int> >pq; queue<pair<int,int> >q; vector<pair<int,int> >vec; int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; int ans1=0x3f3f3f3f,ans2=0; bool check(int x,int y){ if(!a[x][y])return false; if(vis[x][y])return false; int c=0; for(int d=0;d<4;d++)if(vis[x+dx[d]][y+dy[d]])c|=1<<d; return a[x][y]<=fs[c]; } int main(){ scanf("%d%d%d",&M,&n,&m); scanf("%s",s); for(int i=0;i<M;i++)s[i+M]=s[i]; for(int j=0;j<16;j++){ int cnt=0; for(int i=0;i<M*2;i++){ int fl=0; for(int k=0;k<4;k++)if(((1<<k)&j) && t[k]==s[i])fl=1; if(fl)fs[j]=max(fs[j],++cnt); else cnt=0; } if(cnt==M*2)fs[j]=0x3f3f3f3f; } for(int i=1;i<=n*m;i++)fa[i]=i,sz[i]=1; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j])pq.push({-1,id(i,j)}); while(!pq.empty()){ auto [SZ,S]=pq.top(); pq.pop(); if(fa[S]!=S || sz[S]!=-SZ)continue; int sx=(S-1)/m+1,sy=(S-1)%m+1; vec.clear(); vec.push_back({sx,sy}); while(!q.empty())q.pop(); q.push({sx,sy}); vis[sx][sy]=1; int to=-1; while(!q.empty()){ auto [x,y]=q.front();q.pop(); for(int d=0;d<4;d++){ int nx=x+dx[d],ny=y+dy[d]; if(!check(nx,ny))continue; int v=id(nx,ny); if(find(v)!=S){ to=find(v); break; } vis[nx][ny]=1; vec.push_back({nx,ny}); q.push({nx,ny}); } if(to!=-1)break; } for(auto [x,y]:vec)vis[x][y]=0; if(to==-1){ dead[sx][sy]=1; if(vec.size()<ans1)ans1=ans2=vec.size(); else if(vec.size()==ans1)ans2+=vec.size(); } else{ fa[S]=to; sz[to]+=sz[S]; if(!dead[(to-1)/m+1][(to-1)%m+1])pq.push({-sz[to],to}); } vec.clear(); } printf("%d\n%d\n",ans1,ans2); return 0; }
- 1
信息
- ID
- 10167
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者