教主的花园

 

教主的花园

(p1.pas/cpp/in/out)

 

【问题背景】

LHX教主最近总困扰于前来膜拜他的人太多了,所以他给他的花园加上了一道屏障。

 

【问题描述】

可以把教主的花园附近区域抽像成一个正方形网格组成的网络,每个网格都对应了一个坐标(均为整数,有可能为负),若两个网格(x1, y1),(x2, y2)有|x1 – x2| + |y1 – y2| = 1,则说这两个网格是相邻的,否则不是相邻的。

教主在y = 0处整条直线上的网格设置了一道屏障,即所有坐标为(x, 0)的网格。当然,他还要解决他自己与内部人员的进出问题,这样教主设置了N个入口a1, a2, …, aN可供进出,即对于y = 0上的所有网格,只有 (a1, 0),(a2, 0), ……, (aN, 0) 可以通过,之外的所有纵坐标为0的网格均不能通过,而对于(x, y)有y不为0的网格可以认为是随意通过的。

现在教主想知道,给定M个点对(x1, y1),(x2, y2),并且这些点均不在屏障上,询问从一个点走到另一个点最短距离是多少,每次只能从一个格子走到相邻的格子。

 

【输入格式】

输入的第1行为一个正整数N,为屏障上入口的个数。

第2行有N个整数,a1, a2, …, aN,之间用空格隔开,为这N个入口的横坐标。

第3行为一个正整数M,表示了M个询问。

接下来M行,每行4个整数x1, y1, x2, y2,有y1与y2均不等于0,表示了一个询问从(x1, y1)到(x2, y2)的最短路。

 

【输出格式】

输出共包含m行,第i行对于第i个询问输出从(x1, y1)到(x2, y2)的最短路距离是多少。

 

【样例输入】

2

2 -1

2

0 1 0 -1

1 1 2 2

 

【样例输出】

4

2

 

【数据规模】

对于20%的数据,有n,m≤10,ai,xi,yi绝对值不超过100;

对于40%的数据,有n,m≤100,ai,xi,yi绝对值不超过1000;

对于60%的数据,有n,m≤1000,ai,xi,yi绝对值不超过100000;

对于100%的数据,有n,m≤100000,ai,xi,yi绝对值不超过100000000。

=========================

二分法:

分析:

那道题以后想二分,但是答案似乎不满足一个单调性,

是个半单调的,也就是1-答案的编号是单调递减的,

答案的编号-n是单调递增的,所以查找似乎遇到了一些困难.

但是仔细想想,也不是特别困难,因为左半边是单调减的,所以让mid+1,

如果答案比当前答案大那么让右边界往左移,使答案指向单调减的部分.让mid-1,

如果答案比当前答案要大,那么说明是当前在递增序列里面,让左边界往右移.

在两个条件都不满足的时候一定找到一个mid,是答案<左边,>右边,也就是最优答案.

---------------

详见http://blog.sina.com.cn/s/blog_84438fd70100stk3.html

==========================

var
  n,m:longint;
  a:array[1..100000]of longint;
  x1,y1,x2,y2:longint;
procedure init;
begin
  assign(input,'p1.in');
  assign(output,'p1.out');
  reset(input); rewrite(output);
end;

procedure terminate;
begin
  close(input); close(output);
  halt;
end;

procedure qsort(s,t:longint);
var
  m:longint;
  i,j:longint;
  q:longint;
begin
  m:=a[(s+t) shr 1];
  i:=s; j:=t;
  repeat
    while a[i]<m do inc(i);
    while a[j]>m do dec(j);
    if i<=j then
      begin
        q:=a[i];
        a[i]:=a[j];
        a[j]:=q;
        inc(i); dec(j);
      end;
  until i>j;
  if i<t then qsort(i,t);
  if s<j then qsort(s,j);
end;

function pd(a,b:longint):boolean;
begin
  if (a>0) and (b>0) then exit(true);
  if (a<0) and (b<0) then exit(true);
  exit(false);
end;

procedure main;
var
  i:longint;
  l,r,mid,ans:longint;
begin
  readln(n);
  for i:=1 to n do
    read(a[i]);
  qsort(1,n);
  readln(m);
  for i:=1 to m do
    begin
      readln(x1,y1,x2,y2);
      if pd(y1,y2) then writeln(abs(x1-x2)+abs(y1-y2))
      else
      begin
        l:=1; r:=n;
        while l<=r do
          begin
            mid:=(l+r) shr 1;
            ans:=abs(y1-y2)+abs(x1-a[mid])+abs(x2-a[mid]);
            if (mid>1) and (ans>abs(y1-y2)+abs(a[mid-1]-x1)+abs(a[mid-1]-x2))
             then
              r:=mid-1
              else
              if (mid<n) and (ans>abs(y1-y2)+abs(a[mid+1]-x1)+abs(a[mid+1]-x2))
               then
                 l:=mid+1
               else
                 begin
                   l:=mid+1;
                   r:=mid-1;
                 end;
          end;
        writeln(ans);
      end;
    end;
end;

begin
  init;
  main;
  terminate;
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值