Codeforces 1073C——思維
阿新 • • 發佈:2018-11-16
題意:
一個機器人在(0,0),給出n個指令,指令的種類為L R D U,分別代表左移一步 右移一步 下移一步 上移一步,現在給出一個終點(
x,y),要通過改變序列中的一些指令使得機器人最終停在(x,y),並使得花費最小,輸出最小花費(原本就能達到輸出0,無解輸出-1),只允許把一個指令更改為任意一個指令,不允許插入或者刪除指令,花費的計算為改變指令的最大小標減去改變指令的最小下標+1,即區間[最小指令下標,最大指令下標]的長度
1<=n<=2e5,-1e9<=x,y<=1e9
思路:
首先注意到我們要求的實際上是一個最小區間長度,並且這個區間裡的任意指令我們都可以做更改從而使得我們最終到達(x,y),並且注意到這個區間長度越長對我們越有利,所以可以二分割槽間長度進行判斷。
如何判斷一個長度為len的區間是否合法呢?首先我們要列舉區間的位置,然後計算除了這個區間以外的那些位置上的操作可以使機器人到達的座標(這需要維護一個字首和和字尾和),與(x,y)做差絕對值就可以得到兩個數△x △y,我們現在要判斷的就是是否能通過改變當前區間的某些操作使得我們可以恰好湊出△x △y,對於這點我們只要判斷len>=△x+△y && (len-△x-△y)%2==0即可
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; int n; char s[maxn]; int x, y; int prex[maxn], prey[maxn]; int sufx[maxn], sufy[maxn]; bool judge(int len) { for (int i = 1; i + len - 1 <= n; i++) { int l = i-1, r = i+len-1+1; int xx = prex[l] + sufx[r]; int yy = prey[l] + sufy[r]; int dx = abs(x - xx); int dy = abs(y - yy); if (len >= dx + dy && (len-dx-dy)%2 == 0) { return true; } } return false; } int solve() { int l = 1, r = n; while (l <= r) { int mid = (l + r)>>1; if (judge(mid)) r = mid - 1; else l = mid + 1; } if (!judge(l)) return -1; return l; } int main() { scanf("%d", &n); scanf("%s", s+1); scanf("%d%d", &x, &y); memset(prex, 0, sizeof(prex)); memset(prey, 0, sizeof(prey)); memset(sufx, 0, sizeof(sufx)); memset(sufy, 0, sizeof(sufy)); for (int i = 1; i <= n; i++) { if (s[i] == 'L') { prex[i] = prex[i-1]-1; prey[i] = prey[i-1]; } else if (s[i] == 'R') { prex[i] = prex[i-1]+1; prey[i] = prey[i-1]; } else if (s[i] == 'D') { prex[i] = prex[i-1]; prey[i] = prey[i-1]-1; } else { prex[i] = prex[i-1]; prey[i] = prey[i-1]+1; } } for (int i = n; i >= 1; i--) { if (s[i] == 'L') { sufx[i] = sufx[i+1]-1; sufy[i] = sufy[i+1]; } else if (s[i] == 'R') { sufx[i] = sufx[i+1]+1; sufy[i] = sufy[i+1]; } else if (s[i] == 'D') { sufx[i] = sufx[i+1]; sufy[i] = sufy[i+1]-1; } else { sufx[i] = sufx[i+1]; sufy[i] = sufy[i+1]+1; } } if (prex[n] == x && prey[n] == y) { printf("%d\n", 0); } else printf("%d\n", solve()); return 0; }