◇NOIP模拟赛◇robot
Description
小麦最近发明了一个机器人,现在他把机器人拿到一个巨大的测试场地来测试。你可以想像这个测试场地是一个笛卡尔坐标系。现在机器人位于(0,0)处。给机器人一系列指令,机器人将可以根据指令来移动。指令分为四种{S,J,I,Z}。S表示往北移动一步,若当前机器人所在的坐标为(x,y),则机器人将移动到(x,y+1);J表示往南移动一步,若当前机器人所在的坐标为(x,y),则机器人将移动到(x,y-1);I表示往东移动一步,若当前机器人所在的坐标为(x,y),则机器人将移动到(x+1,y);Z表示往西移动一步,若当前机器人所在的坐标为(x,y),则机器人将移动到(x-1,y)。
在测试场地上有许多测距站,可以测出该点到机器人所在位置的曼哈顿距离。A点(x1,y1)和B点(x2,y2)的曼哈顿距离,即为|x1-x2|+|y1-y2|。
现在给出机器人的M条指令,机器人每走一步,测距站都会测一次距离。求每条指令后所有测距站测的的距离之和。
Input
给出整数N,M(1<=N<=100000,1<=M<=300000)。N表示测距站的个数,M表示指令条数。
接下来N行,每行给出两个整数,表示该测距站的x,y坐标。
再接下来一行,包含M个字符,表示M条命令。
Output
M行,每行包含一个整数,表示所有测距站测的的距离之和。
Sample Input
1 3
0 -10
ISI
Sample Output
11
12
13
题目解析
这道题主要是考察算法效率,如果直接暴力模拟的话是肯定超时的。(先把注意点说完吧)开long long信不信由你。(再说一下什么是曼哈顿距离吧)令A、B的曼哈顿距离为 F(A,B),在平面直角坐标系上,则
F(A,B)=|xA−xB|+|yA−yB|
。由于每一次移动得到的值都与上一次移动得到的值有关联。
突然想水一篇博客
由于我们并不需要知道每一个点的确切位置,甚至不需要匹配每一个点的坐标!我们只需要知道对于机器人相对位置(上下左右)的点的数量就可以了——可以在输入时就预处理出来。由于我们不需要知道每一个点的确切坐标,也就是说我们只需要知道横坐标为x以及纵坐标为y的点有多少个就行了。我们可以把它们存在数组里(totx[i]表示横坐标为i的点的个数,toty[i]表示纵坐标为i的点的个数)。但是童鞋们是否发现坐标有负数?这个坑,也就是说不能用数组存。还好有C++,STL有一个神奇的容器——map < int > 。它的下标是一个任意的int变量,哪怕是负数!!!(可惜速度有点慢)现在所有问题都解决了。
现在来分析一下规律——我们不妨设机器人当前的总距离为
Sum
下一步行进的方向有
X
个点,行进方向的另一边有
?代码?(不叫“样例程序”了)
/*Lucky_Glass*/
#include<cstdio>
#include<iostream>
#include<map>
#define fabs(a) (a>0? a:-a)
using namespace std;
int Num_Point,Num_Code,Up_X,Down_X,Left_X,Right_X;
long long Sum;
map<int,long> X,Y;
char Code[300005];
int main()
{
scanf("%d%d",&Num_Point,&Num_Code);
for(int i=0,x,y;i<Num_Point;i++)
{
scanf("%d%d",&x,&y),X[x]++,Y[y]++;
if(y>0) Up_X++;if(y<0) Down_X++;if(x>0) Right_X++;if(x<0) Left_X++;
Sum+=fabs(x)+fabs(y);
}
cin>>Code;
int x=0,y=0;
for(int i=0;i<Num_Code;i++)
{
switch(Code[i])
{
case 'I':
Left_X+=X[x];
Sum=Sum+Left_X-Right_X;
Right_X-=X[++x];
break;
case 'S':
Down_X+=Y[y];
Sum=Sum+Down_X-Up_X;
Up_X-=Y[++y];
break;
case 'Z':
Right_X+=X[x];
Sum=Sum+Right_X-Left_X;
Left_X-=X[--x];
break;
case 'J':
Up_X+=Y[y];
Sum=Sum+Up_X-Down_X;
Down_X-=Y[--y];
break;
}
printf("%lld\n",Sum);
}
return 0;
}
The End
Thanks for reading!
-Lucky_Glass