题目大意:
给定一个机器人的行走方式
你需要取走一段区间
但要保证取走这段区间后机器人最终到达的终点位置是不变的
问这段区间最短时是哪一段
解题思路:
易得,如果重复走到了某些已经走过的点,那么肯定就有一段区间可以被删除
但是行走次数最大有2e5,即用数组记录坐标状态的话起码要开4e5*4e5的空间,显然不可能
所以可以用map储存上一次走到某个坐标是第几步
那么每次只要判断当前的坐标是否已经被走过即可,走过的话就尝试更新答案
因为map中未调用过的int值为0
所以让原点的步数设置为1防止混淆
初始设置 l=0,r=n+1去最大化这个答案区间,便于第一次判断得以执行
然后,遍历这个字符串,如果发现某个点已经走过了,取出这个步数为 d
可以得到 d+1~i 这一段是可以删除的(d步不可取,因为那一步走完才能到达这个点)
那么就拿 i-(d+1) 和 r-l 作比较,即当 r-l>i-(d+1) => r-l>=i-d 时,更新lr答案
最后把第一步的步数减回去就可以作为答案了(l=0,说明不存在)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 struct P{ 5 int x,y; 6 bool operator < (const P& a) const{ 7 return x<a.x||x==a.x&&y<a.y; 8 } 9 bool operator == (const P& a) const{ 10 return x==a.x&&y==a.y; 11 } 12 }; 13 string s; 14 void solve(){ 15 int i,n,l,r,d; 16 cin>>n>>s; 17 map<P,int> mp; 18 P pd; 19 pd.x=pd.y=0; 20 mp[pd]=1; 21 l=0;r=n+1;//先最大化答案区间 22 s=" "+s;//下标向右移动2位,便于直接把i当作步数 23 for(i=2,n++;i<=n;i++){ 24 if(s[i]=='L') 25 pd.x--; 26 else if(s[i]=='R') 27 pd.x++; 28 else if(s[i]=='U') 29 pd.y++; 30 else 31 pd.y--; 32 d=mp[pd]; 33 if(d>0){//这个点走过 34 if(r-l>=i-d) 35 l=d+1,r=i; 36 } 37 mp[pd]=i; 38 } 39 if(l==0) 40 cout<<"-1\n"; 41 else 42 cout<<l-1<<' '<<r-1<<'\n';//因为原点步数为1,把差值减回去 43 } 44 int main(){ 45 ios::sync_with_stdio(0); 46 cin.tie(0);cout.tie(0); 47 int T;cin>>T;while(T--) 48 solve(); 49 50 return 0; 51 }
来源:https://www.cnblogs.com/stelayuri/p/12262316.html