题解 [ABC341C] Takahashi Gets Lost
本来不想写这个题题解的,但是偶然发现在洛谷上是最优解?
这个题和 P6226 [BalticOI 2019 Day1] 潜艇有一定的相似之处。
题意
海洋是一个 $H \times W$ 的网格,其中 . 代表岛屿,# 代表水域,高桥只能在陆地上行走。
高桥坠落到了一个陆地上,接着他会依次沿着给定的字符串 $T$ 进行移动,其中字符串中的 LRUD,分别表示向左、向右、向上、向下移动一个单元格。
你不知道高桥坠落的位置,所以请求出高桥移动后可能的位置数量。
分析
考虑动态规划。
状态设计
设 $f_{i,x,y}$ 表示执行完前 $i$ 个操作后位置 $(x,y)$ 能否作为终点。
设命令字符串为 $s$,原地图为 $a$。
状态转移
$$ f_{i,x,y}=f_{0,x,y} \operatorname{and} \begin{cases} f_{i-1,x+1,y} & T_i=\texttt{U}\\ f_{i-1,x-1,y} & T_i=\texttt{D}\\ f_{i-1,x,y+1} & T_i=\texttt{L}\\ f_{i-1,x,y-1} & T_i=\texttt{R}\\ 0 & \text{otherwise} \end{cases} $$
初始状态
$$ $$
$$ f_{0,x,y}= \begin{cases} 1 & a_{x,y}=\texttt{.}\\ 0 & a_{x,y}=\texttt{\#}\\ 0 & \text{otherwise} \end{cases} $$
经过观察可以发现状态转移只需要两维,所以可以直接滚动省略掉第一维。
时间复杂度 $O(HWN)$,但是因为 std::bitset 砍掉了一个大常数。
代码
//the code is from chenjh
#include<cstdio>
#include<bitset>
using namespace std;
int n,m,k;//这里的 n,m,k 分别对应题面中的 H,W,N。
bitset<505>c[505],b[505];
char t[505];
int main(){
scanf("%d%d%d %s",&n,&m,&k,t);
for(int i=0;i<n;i++){
scanf(" ");
for(int j=0;j<m;j++) b[i][j]=c[i][j]=getchar()=='.';
}
for(int i=0;i<k;i++){
if(t[i]=='L'){
for(int i=0;i<n;i++) b[i]=(b[i]>>1)&c[i];
}
else if(t[i]=='R'){
for(int i=0;i<n;i++) b[i]=(b[i]<<1)&c[i];
}
else if(t[i]=='U'){
for(int i=0;i<n-1;i++) b[i]=b[i+1]&c[i];
b[n-1].reset();
}
else if(t[i]=='D'){
for(int i=n-1;i>0;--i) b[i]=b[i-1]&c[i];
b[0].reset();
}
}
int ans=0;
for(int i=0;i<n;i++) ans+=b[i].count();//统计有多少个点可能存在。
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号