題目大意:
給定一個機器人的行走方式
你需要取走一段區間
但要保證取走這段區間后機器人最終到達的終點位置是不變的
問這段區間最短時是哪一段
解題思路:
易得,如果重復走到了某些已經走過的點,那么肯定就有一段區間可以被刪除
但是行走次數最大有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,說明不存在)
對於這里的結構體運算符重載,因為使用map需要告知大小關系才能存入這顆紅黑樹進行排序(map是會根據鍵值進行大小排序先的,然后進行二分查找)
所以就重載了小於運算符,先按照x從小到大排,如果x相同按照y從小到大排
這樣就可以在之后二分查找時能夠准確找到值
然后是對等於的重載,在查找的最后需要判斷找到的位置的鍵值和輸入的是否相同(因為如果找不到輸入的鍵值的話是會返回空的——int類型即數值0)
所以要重載等於運算符
#include<bits/stdc++.h> using namespace std; typedef long long ll; struct P{ int x,y; bool operator < (const P& a) const{ return x<a.x||x==a.x&&y<a.y; } bool operator == (const P& a) const{ return x==a.x&&y==a.y; } }; string s; void solve(){ int i,n,l,r,d; cin>>n>>s; map<P,int> mp; P pd; pd.x=pd.y=0; mp[pd]=1; l=0;r=n+1;//先最大化答案區間 s=" "+s;//下標向右移動2位,便於直接把i當作步數 for(i=2,n++;i<=n;i++){ if(s[i]=='L') pd.x--; else if(s[i]=='R') pd.x++; else if(s[i]=='U') pd.y++; else pd.y--; d=mp[pd]; if(d>0){//這個點走過 if(r-l>=i-d) l=d+1,r=i; } mp[pd]=i; } if(l==0) cout<<"-1\n"; else cout<<l-1<<' '<<r-1<<'\n';//因為原點步數為1,把差值減回去 } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); int T;cin>>T;while(T--) solve(); return 0; }