【Codeforces1117C_CF1117C】Magic Ship(构造)
题目:
考的时候很困,开局半小时后才过A,只做出来AB,排名3000+,掉了119……半夜体验极差。
翻译:
你是一个船长。最初你在点 \((x_1,y_1)\) (显然,大海上的所有点都可以用平面直角坐标描述),你想去点 \((x_2,y_2)\) 。
你看了天气预报——一个长为 \(n\) 的字符串 \(s\),只包含字母 U, D, L 和 R 。这些字母表示风向。并且,这个天气预报是循环的。例如,第一天风向是 \(s_1\) ,第二天是 \(s_2\) ,第 \(n\) 天是 \(s_n\) ,则第 \(n+1\) 天又是 \(s_1\) ,以此类推。
船的坐标按照如下方式改变:
如果风向是 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\) 个单位或待在原地。船的位移与风向会相加。如果船待在原地,则只计算风向对船的影响。例如,如果风向是 U ,船向 L 移动,则它会从 \((x,y)\) 移动到 \((x-1,y+1)\) ;如果船向 U 移动,则它会移动到 \((x,y+2)\) 。
你的任务是确定移动到 \((x_2,y_2)\) 所需的最少天数。
输入
第一行包含两个整数 \(x_1,y_1\ (0\leq x_1,y_1\leq 1e9)\) ——船的初始坐标。
第二行包含两个整数 \(x_2,y_2\ (0\leq x_2,y_2\leq 1e9)\) ——目的地的坐标。
保证初始坐标与目的地的坐标不同。
第三行包含一个整数 \(n\ (1\leq n \leq 10^5)\) ——字符串 \(s\) 的长度。
第四行包含字符串 \(s\) ,只包含字母 U, D, L 和 R 。
输出
输出一行,移动到 \((x_2,y_2)\) 所需的最少天数。
如果不可能输出 \(-1\) 。
分析:
(以下这些“显然”的结论我在考场上一个都没看出来……)
首先答案具有可二分性。因为到达终点后每天都往与当天风向相反的方向航行就可以停留在原地。
由于无论在什么地方,风的影响都是一样的。所以相当于先被风吹 \(t\) 天,然后再在无风的情况下航行不超过 \(t\) 天到终点。即,算出被风吹 \(t\) 天后的坐标,如果到终点的曼哈顿距离不超过 \(t\) ,说明 \(t\) 合法,向下二分,否则向上二分。
通过类似前缀和的方式算出前 \(i\ (1\leq i \leq n)\) 天在风的影响下两维坐标的改变量 \(sumx[i]\) 和 \(sumy[i]\) ,则 \(t\) 天后的坐标是 \((x_1+\lfloor\frac{t}{n}\rfloor sumx[n]+sumx[t\mod n],y_1+\lfloor\frac{t}{n}\rfloor sumy[n]+sumy[t\mod n])\) 。
代码:
二分上界记着开充分大……
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
namespace zyt
{
typedef long long ll;
const int N = 1e5 + 10;
int x1, y1, x2, y2, n;
char s[N];
int sumx[N], sumy[N];
inline ll abs(const ll x)
{
return x < 0 ? -x : x;
}
int work()
{
scanf("%d%d%d%d%d%s", &x1, &y1, &x2, &y2, &n, s + 1);
for (int i = 1; i <= n; i++)
{
sumx[i] = sumx[i - 1], sumy[i] = sumy[i - 1];
if (s[i] == 'U')
++sumy[i];
else if (s[i] == 'D')
--sumy[i];
else if (s[i] == 'L')
--sumx[i];
else
++sumx[i];
}
ll l = 1, r = 1e18, ans = -1;
while (l <= r)
{
ll mid = (l + r) >> 1;
if (abs(x1 + (ll)sumx[n] * (mid / n) + sumx[mid % n] - x2)
+ abs(y1 + (ll)sumy[n] * (mid / n) + sumy[mid % n] - y2) <= mid)
r = mid - 1, ans = mid;
else
l = mid + 1;
}
printf("%lld", ans);
return 0;
}
}
int main()
{
return zyt::work();
}