Maze 1D 题解
题目大意
在数轴上给定一串行动指令,类型有两种:向左移动一个单位 / 向右移动一个单位。要求最后一步到达一个没有到达过的位置。可以在数轴上放置若干个障碍物阻碍移动,问在放置的障碍物最少的情况下有多少放置方式。
思路分析
结论题。
结论一:障碍物的数目不多于 \(1\)。
- 证明:
若可以在不放置任何障碍物的情况下满足要求,那么障碍物的数目为 \(0\),放置方式为 \(1\)。
否则,一定可以通过放置恰好一个障碍物达成目标。
考虑放置两个障碍物的情况:
- 二者都在原点同侧:
此时离原点更远的障碍物没有任何作用,可以舍去。
- 一个在左一个在右:
如果两个障碍物都被触碰到,那么意味着所有可以被到达的地方均被到达过,不满足要求。
反之,如果存在一个障碍物没有被触碰到,那么它没有作用,可以舍去。
更多障碍物的情况可以归结为这两种情况的组合。
结论二:若最后一步往左,那么障碍物在原点右侧,否则障碍物在原点左侧。
- 证明:
考虑反证法:
假设最后一步往左,且障碍物在原点左侧:
考虑到中途一定会触碰障碍物,所以总到达的区间是:左侧障碍物,右侧不确定,但最后一步移动起始的位置一定位于这个区间内,又因为区间左侧被封死,所以不可能到达新的位置。与要求矛盾,故结论成立,右侧同理。
结论三:障碍物放置的合法区间一定是从原点到某一点的连续区间。
- 证明:
考虑到移动序列长度有限,故障碍物一定存在一个最远的可以放置的点,那么将障碍物从这个点向原点靠近,抵消的不利操作一定会越来越多,考虑到其单调性,结论显然成立。
在有了这三个结论之后这题就比较简单了:
二分找出最远的能放置的点,二分的判定直接暴力模拟即可。
代码
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1001000;
int n;
int vis[N<<1];
char inp[N];
bool walk(int B){//模拟
int x=N,res;
for(int i=1;i<=n;i++){
vis[x]=1;
if(inp[i]=='R'&&x+1!=B) x++;
if(inp[i]=='L'&&x-1!=B) x--;
}
res=!vis[x];
x=N;
for(int i=1;i<=n;i++){//清空
vis[x]=0;
if(inp[i]=='R'&&x+1!=B) x++;
if(inp[i]=='L'&&x-1!=B) x--;
}
return res;
}
int main(){
scanf("%s",inp+1);
n=strlen(inp+1);
if(walk(-N)){cout<<"1\n";return 0;}//先判断不放合不合法
if(inp[n]=='L'){//看最后一步往哪边
int l=N,r=N*2;
while(l<r){
int mid=(l+r+1)>>1;
if(walk(mid)) l=mid;
else r=mid-1;
}
cout<<l-N<<'\n';
}
if(inp[n]=='R'){
int l=1,r=N;
while(l<r){
int mid=(l+r)>>1;
if(walk(mid)) r=mid;
else l=mid+1;
}
cout<<N-r<<'\n';
}
return 0;
}

浙公网安备 33010602011771号