您的位置:首页 > 其它

[日常训练] 距离之和

2017-07-17 17:03 176 查看

【问题描述】

想象一个机器人位于二维空间。初始时,机器人在(0,0)。有4个命令S,J,I,Z。具体的,如果机器人在(x,y),在收到S命令之后,移动到(x,y+1),收到J之后,移动到(x,y-1),I命令之后移动到(x+1,y),Z命令之后移动到(x-1,y)。在这个二维空间有n个固定的点,在每个命令之后,每个固定点会计算自己与机器人的曼哈顿距离,然后返回这些距离的总和。

PS:两个点(x1,y1)和(x2,y2)的曼哈顿|x1-x2|+|y1-y2|。

【输入格式】

第一行是正整数n和m。
接下来n行,每行两个整数,表示控制点的坐标,有些控制点坐标可能相同。
接下来一行,一个长度为m的字符串,表示机器人依次接受到的命令。


【输出格式】

输出m行,每行一个整数,第i行表示第i个命令执行以后所有控制点到机器人的曼哈顿距离之和。


【输入样例】

3 5
0 0
1 1
1 -1
SIJJZ


【输出样例】

5
4
3
4
5


【数据范围与约定】

对于40%的数据:n<=1000,m<=5000。
对于100%的数据:n <= 100000, m <= 300000。


(感觉这题很乱搞???)

【分析】

考虑机器人每走一步都以其为原点建立平面直角坐标系,先暴力每个点到机器人的曼哈顿距离之和。

然后预处理出x轴上下方、y轴左右方、xy轴上以及每一行每一列的固定点个数。

记此时机器人的坐标为(tx,ty),则当机器人向右走时,y轴以及y轴左方的固定点到机器人的距离都增加1,y轴右方的固定点到机器人的距离都减少1,同时现在y轴就变为y=tx+1,y轴左方的固定点个数要加上原y轴的固定点个数,y轴右方的固定点个数要减去原y轴的固定点个数,现在y轴上的固定点个数可以通过之前每一行每一列的预处理更新。而当机器人向其它方向走时,也是同理。

这里每一行每一列的固定点个数用的是map存储,这样的总复杂度为O(mlogn)

【代码】

#include <iostream>
#include <cstdio>
#include <map>

using namespace std;
typedef long long ll;

map<int, int> a, b;

const int N = 1e5 + 5;

char s[N * 3];
int lft, rig, upt, dwn, ex, ey, tx, ty, n, m;
ll Ans;

inline int Abs(const int &x)
{
return x < 0 ? -x : x;
}

inline int get()
{
char ch; int res = 0; bool f = false;
while (((ch = getchar()) < '0' || ch > '9') && ch != '-');
if (ch == '-') f = true;
else res = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9')
res = (res << 3) + (res << 1) + ch - '0';
return f ? -res : res;
}

inline void put(ll x)
{
if (x > 9) put(x / 10);
putchar(x % 10 + 48);
}

int main()
{
freopen("robot.in", "r", stdin);
freopen("robot.out", "w", stdout);
n = get(); m = get(); int u, v;
for (int i = 1; i <= n; ++i)
{
u = get(); v = get();
if (u < 0) lft++;
else if (u > 0) rig++;
else ey++;
if (v > 0) upt++;
else if (v < 0) dwn++;
else ex++;
Ans += Abs(u) + Abs(v);
a[u]++; b[v]++;
}
scanf("%s", s + 1);
for (int i = 1; i <= m; ++i)
{
switch(s[i])
{
case 'S': ty++;
Ans += dwn - upt + ex;
dwn += ex;
upt -= (ex = b[ty]);
break;
case 'J': ty--;
Ans += upt - dwn + ex;
upt += ex;
dwn -= (ex = b[ty]);
break;
case 'I': tx++;
Ans += lft - rig + ey;
lft += ey;
rig -= (ey = a[tx]);
break;
case 'Z': tx--;
Ans += rig - lft + ey;
rig += ey;
lft -= (ey = a[tx]);
break;
}
put(Ans), putchar('\n');
}
fclose(stdin); fclose(stdout);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数学