题解 [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;
}
posted @ 2024-02-18 08:48  Chen_Jinhui  阅读(26)  评论(0)    收藏  举报  来源