CodeForce Educational round Div2 C - Vasya and Robot
题意:给你长度为n的字符串,每个字符为L, R, U, D。给你终点位置(x, y)。你每次出发的起点为(0, 0)。你可以改动每次的移动方向到达(x,y)点。求改动的MaxID-MinID+1是多少。
思路:
先分别求x轴,y轴上的前缀和,偏于之后判断区间是否满足条件。详细见代码。
固定左端点,二分枚举右端点。判断左右端点的区间是否能够达成目标(区间长度是否大于未完成量,奇偶性是否相同)
注意点:
strlen是O(n)的复杂度,超时了。
之前没遇到过固定一个点,然后另一个点二分逼近值的。
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <cstdio> #include <vector> #include <queue> #include <set> #include <map> #include <stack> #define ll long long #define local using namespace std; const int MOD = 1e9+7; const int inf = 0x3f3f3f3f; const double PI = acos(-1.0); const int maxn = 2e5+10; int n; ll endx, endy; ll total; char str[maxn]; int sumx[maxn]; int sumy[maxn]; bool ok(int l, int r) { int nowx = sumx[n-1]-sumx[r]; int nowy = sumy[n-1]-sumy[r]; if (l > 0) { nowx += sumx[l-1]; nowy += sumy[l-1]; } ll diff = abs(endx-nowx)+abs(endy-nowy); if (diff <= r-l+1 && ((diff&1))==((r-l+1)&1)) return 1; else return 0; } int main() { #ifdef local if(freopen("/Users/Andrew/Desktop/data.txt", "r", stdin) == NULL) printf("can't open this file!\n"); #endif scanf("%d", &n); scanf("%s", str); scanf("%lld%lld", &endx, &endy); total = abs(endx)+abs(endy);//总的步数 //如果两者奇偶性不同也不行 if (total>n || ((total&1) != (n&1))) { printf("-1\n"); return 0; } sumx[0] = 0; sumy[0] = 0; int len = int(strlen(str));//strlen(str)是O(n)的复杂度 orz... for (int i = 0; i < len; ++i) { int incx = 0; int incy = 0; if (str[i] == 'U') { incy = 1; } else if (str[i] == 'R') { incx = 1; } else if (str[i] == 'D') { incy = -1; } else { incx = -1; } if (i) { sumx[i] += sumx[i-1]+incx; sumy[i] += sumy[i-1]+incy; } else { sumx[i] = incx; sumy[i] = incy; } } if (sumx[n-1]==endx && sumy[n-1]==endy) { printf("0\n"); return 0; } int mn = inf; //枚举点 for (int i = 0; i < n; ++i) { int l = i-1; int r = n-1; while (r-l > 1) { int m = (l+r)>>1; if (ok(i, m)) { r = m; } else { l = m; } } //判断一下r是否可行 if (ok(i, r)) mn = min(mn, r-i+1); } printf("%d\n", mn); #ifdef local fclose(stdin); #endif return 0; }