Loading

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;
}
posted @ 2023-07-18 21:06  TKXZ133  阅读(31)  评论(0)    收藏  举报