AT_abc443_e [ABC443E] Climbing Silver 题解
先考虑不存在墙时怎么做,我们可以直接 bfs 搜出所有可以到达的点。接下来,考虑墙怎么处理,根据题意,一个墙 \((i,j)\) 可以变为空地,当且仅当 \(\forall k>i\) 满足 \((k,j)\) 都是空地,于是我们分两类讨论:
- 在原图上 \(\forall k>i\) 满足 \((k,j)\) 都是空地,即 \((i,j)\) 在这第 \(j\) 列中没有后继墙了,那此时 \((i,j)\) 可以直接变为空地,且在 bfs 过程中标为可到达;
- 相反,在原图上 \(\exists k>i\) 满足 \((k,j)\) 是墙,即 \((i,j)\) 在这第 \(j\) 列中有后继墙,我们找到最小的 \(k>i\) 满足 \((k,j)\) 是墙,如果 \((k,j)\) 是可到达的,证明第 \(j\) 列中 \((k,j)\) 及之后的墙已经全部成为空地,所以 \((i,j)\) 可以直接变为空地,且在 bfs 过程中标为可到达,如果 \((k,j)\) 是不可到达的,那么同理 \((i,j)\) 也是不可到达的。
我们对于后继墙可以使用 vector 维护每列墙的行号,每次二分查找第一个后继墙即可,时间复杂度为 \(O(n^2\log n)\)。
CODE
#include<bits/stdc++.h>
using namespace std;
int t,n,c;
string s;
bitset<3005> book[3005],a[3005];
vector<int> e[3005];
void bfs(){
queue<pair<int,int>> q;
q.push({n,c});
book[n][c]=1;
while(!q.empty()){
auto u=q.front();
q.pop();
if(u.first==1)continue;
for(int i=u.second-1;i<=u.second+1;i++){
if(i<=0||i>n||book[u.first-1][i])continue;
if(a[u.first-1][i]){
auto it=upper_bound(e[i].begin(),e[i].end(),u.first-1);
if(it==e[i].end()){
q.push({u.first-1,i});
book[u.first-1][i]=1;
}else if(book[*it][i]){
q.push({u.first-1,i});
book[u.first-1][i]=1;
}
}
else{
q.push({u.first-1,i});
book[u.first-1][i]=1;
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cout.tie(0),cout.tie(0);
cin>>t;
while(t--){
cin>>n>>c;
for(int i=1;i<=n;i++)e[i].clear();
for(int i=1;i<=n;i++){
cin>>s;
for(int j=0;j<n;j++){
a[i][j+1]=(s[j]=='#');
if(a[i][j+1])e[j+1].push_back(i);
}
book[i].reset();
}
bfs();
for(int i=1;i<=n;i++)cout<<book[1][i];
cout<<endl;
}
return 0;
}

浙公网安备 33010602011771号