[日常训练] 距离之和
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; }
相关文章推荐
- 日常基本功训练方法及要求与标准。
- 日常训练20161031 量化交易 trade
- 日常训练20161012 醉酒
- 日常训练 20170606 魔法手镯
- 日常训练 20170619 被删除量子化粉碎未出生的回文矩阵
- 日常训练 20170708 贝加尔湖畔baikal
- 利用python对中文文本数据进行LDA训练、计算概率距离
- [日常训练] 树上的游戏
- [日常训练] Tree
- 日常训练-2016Multi-university第十场
- 日常训练 20170606 极地旅行社
- 【20101106】动态规划训练:字串距离
- [日常训练] tty的方程
- 日常训练 Idiot 的方程
- 日常训练 20170612 星之船
- 日常训练 水箱
- 日常训练 20161102 隔离区
- 日常训练 Idiot 的集合
- 日常训练20161018 证据
- [日常训练] 太空飞船