Educational Codeforces Round 53 (Rated for Div. 2) C. Vasya and Robot 二分+前後綴預處理
阿新 • • 發佈:2018-11-13
題意:
給定長度為n的字串,每個字元表示朝上下左右四個方向前進,給定一個目標位置,找一個最小的區間,使得改變這個區間的若干個字元,使得整個串的操作能到達目標位置只需要輸出最小區間長度
思路:
首先暴力的想法就是列舉所有的區間,這樣這個區間兩邊就會有一些操作不會改變,然後我們根據這些操作得到一個位置,跟目標位置比較,看看我們能否通過設定這個區間達到目標位置,顯然複雜度很高;
然後就可以想到二分,二分割槽間長度,然後對於當前區間長度,列舉開始位置,檢查是否可以到達目標位置,這樣的話還是按照上述暴力的思路,我們得知道不改變的操作能到達的位置,這就需要我們預處理字首和字尾能對上下左右四個方向做出的貢獻,可以得到一個“位置”,然後檢查是否可行
#include<bits/stdc++.h> using namespace std; #define out fflush(stdout) #define fast ios::sync_with_stdio(0),cin.tie(0); #define FI first #define SE second typedef long long ll; typedef pair<int,int> P; const int maxn = 2e5 + 7; const int INF = 0x3f3f3f3f; int n, x, y; char s[maxn]; int x1[maxn], y1[maxn]; int x2[maxn], y2[maxn]; bool ok(int len) { for(int i = 1; i <= n; ++i) { int j = i + len - 1; if(j > n) break; int dx = x1[i-1] + x2[j + 1], dy = y1[i-1] + y2[j+1]; // cout << i << " : " << dx << " +++ " << dy << endl; int cnt = abs(dx-x) + abs(dy-y); if(cnt <= len && (len-cnt) % 2 == 0) return true; } return false; } void init() { x1[0] = 0, y1[0] = 0; for(int i = 1; i <= n; ++i) { if(s[i] == 'U') { x1[i] = x1[i-1]; y1[i] = y1[i-1] + 1; } if(s[i] == 'D') { x1[i] = x1[i-1]; y1[i] = y1[i-1] - 1; } if(s[i] == 'L') { x1[i] = x1[i-1] - 1; y1[i] = y1[i-1]; } if(s[i] == 'R') { x1[i] = x1[i-1] + 1; y1[i] = y1[i-1]; } } x2[n+1] = 0, y2[n+1] = 0; for(int i = n; i >= 1;--i) { if(s[i] == 'U') { x2[i] = x2[i+1]; y2[i] = y2[i+1] + 1; } if(s[i] == 'D') { x2[i] = x2[i+1]; y2[i] = y2[i+1] - 1; } if(s[i] == 'L') { x2[i] = x2[i+1] - 1; y2[i] = y2[i+1]; } if(s[i] == 'R') { x2[i] = x2[i+1] + 1; y2[i] = y2[i+1]; } } } int main() { scanf("%d", &n); scanf("%s", s+1); scanf("%d%d", &x, &y); if(abs(x) + abs(y) > n) { return 0*puts("-1"); } init(); int l = 0, r = n, ans = -1; while(l <= r) { int mid = (l + r) / 2; // cout << mid << " : "; if(ok(mid)) { // cout << " YES " << endl; ans = mid; r = mid - 1; } else { // cout << " NO " << endl; l = mid + 1; } } printf("%d\n", ans); return 0; }