◆考试题目◆◇NOIP模拟赛◇robot(机器人)

◇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)=|xAxB|+|yAyB| 。由于每一次移动得到的值都与上一次移动得到的值有关联。
突然想水一篇博客
由于我们并不需要知道每一个点的确切位置,甚至不需要匹配每一个点的坐标!我们只需要知道对于机器人相对位置(上下左右)的点的数量就可以了——可以在输入时就预处理出来。由于我们不需要知道每一个点的确切坐标,也就是说我们只需要知道横坐标为x以及纵坐标为y的点有多少个就行了。我们可以把它们存在数组里(totx[i]表示横坐标为i的点的个数,toty[i]表示纵坐标为i的点的个数)。但是童鞋们是否发现坐标有负数?这个坑,也就是说不能用数组存。还好有C++,STL有一个神奇的容器——map < int > 。它的下标是一个任意的int变量,哪怕是负数!!!(可惜速度有点慢)现在所有问题都解决了。
现在来分析一下规律——我们不妨设机器人当前的总距离为 Sum 下一步行进的方向有 X 个点,行进方向的另一边有 Y 个点。我们很容易发现——移动后的机器人相对于上一位置,离它行进方向背面的点的距离都增加了1,而离它行进方向的点的距离都减少了1,那么现在的位置的总和 Sum+YX 。注意要先移动机器人,更新 XY 后再计算。


?代码?(不叫“样例程序”了)

/*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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值