Codeforces C. Vasya and Robot+二分
阿新 • • 發佈:2018-11-17
題目連結:http://codeforces.com/contest/1073/problem/C
題目大意:機器人有4種操作
U — (x,y)->(x,y+1)
D — (x,y)->(x,y−1)
L — (x,y)->(x−1,y)
R — (x,y)->(x+1,y)
現在給你一段操作序列,再給你一個目標座標點,問你改變序列中的最小長度,讓機器人到達目標點,如果不能到達,輸出-1,不用改變輸出0
L U L UU 所有改變的長度為3
思路:先從前到後,把從開始到當前位置能到達x1, y1的位置記錄下來。
再先從後到前,把從結束位置到當前位置能到達x2, y2的位置記錄下來。
先判斷是否能改變序列到達目標點,如果序列長度len< abs(x-x1-x2)+abs(y-y1-y2)
一定不能到達,如果len>abs(x-x1-x2)+abs(y-y1-y2),必須(len-abs(x-x1-x2)- abs(y-y1-y2))%2==0才能到達。
當時只想到了nn的做法:兩重迴圈,把每一種情況都考慮到。但是n<=210^5肯定要T。
因為長度len是解,那麼所有大於len也一定是解
所有可以二分列舉長度,再去原序列中迴圈找這個序列,判斷是否滿足解。
思考:如果題目中的資料範圍n*lgn能過,那麼除了STL,還可以考慮二分
#include<bits/stdc++.h> #define maxn 1000010 using namespace std; struct A { int x; int y; }; A a[200005]={{0}}, b[200005]={{0}}; char ch[200005]; int n, x, y; int ef(int k) { for(int i=0;i<=n-k;i++) { A t; t.x=a[i].x+b[i+k+1].x; t.y=a[i].y+b[i+k+1].y; int len=abs(x-t.x)+abs(y-t.y); if(len<=k&&len%2==k%2)/*判斷是否滿足解*/ { return 1; } } return -1; } int main() { scanf("%d",&n); scanf("%s",ch+1); scanf("%d%d",&x,&y); if(abs(x)+abs(y)>n) { printf("-1\n"); return 0; } a[0]={0}; for(int i=1;i<=n;i++)/*從前到後掃描**/ { a[i]=a[i-1]; if(ch[i]=='U') a[i].y=a[i].y+1; else if(ch[i]=='D') a[i].y=a[i].y-1; else if(ch[i]=='L') a[i].x=a[i].x-1; else if(ch[i]=='R') a[i].x=a[i].x+1; } b[n+1]={0}; for(int i=n;i>=1;i--)/*從後到前掃描*/ { b[i]=b[i+1]; if(ch[i]=='U') b[i].y=b[i+1].y+1; else if(ch[i]=='D') b[i].y=b[i+1].y-1; else if(ch[i]=='L') b[i].x=b[i+1].x-1; else if(ch[i]=='R') b[i].x=b[i+1].x+1; } int l=0, r=n, k=-1; while(l<=r)/*二分*/ { int mod=(l+r)/2; if(ef(mod)<0) l=mod+1; else r=mod-1, k=mod; } printf("%d\n",k); return 0; }
加粗樣式