[二分][排序] JZOJ P1792 教主的花园

Description

【问题背景】
  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),并且这些点均不在屏障上,询问从一个点走到另一个点最短距离是多少,每次只能从一个格子走到相邻的格子。

Input

  输入的第1行为一个正整数N,为屏障上入口的个数。
  第2行有N个整数,a1, a2, …, aN,之间用空格隔开,为这N个入口的横坐标。
  第3行为一个正整数M,表示了M个询问。
  接下来M行,每行4个整数x1, y1, x2, y2,有y1与y2均不等于0,表示了一个询问从(x1, y1)到(x2, y2)的最短路。

Output

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

Sample Input

2
2 -1
2
0 1 0 -1
1 1 2 2

Sample Output

4
2 

Hint

【数据规模】
  对于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。

题解

  • 题目大意就是在一个平面直角坐标系中x轴上是一道屏障,但上面有n个开头,要求两个点的距离
  • 显然,这题可以分类讨论来做
  • ①两个点的y坐标同号,直接求曼哈顿距离输出
  • 如果不行,则二分一个在中间的开口
  • ②如果这个开口位于两个点中间,求出两个点分别到开口的曼哈顿距离相加并输出
  • ③否则判断一下它距离哪一个端点近,就由哪里绕过去
  • 虽然此时的pos值不一定准确,但十分接近,真实值一定出现在pos-1,pos,pos+1中,求最小值输出就好了

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 using namespace std;
 5 int n,m,a[100010];
 6 int abs(int a){ return a<0?-a:a;}
 7 int find(int x)
 8 {
 9     int l=1,r=n,k=n;
10     while(l<=r)
11     {
12         int mid=(l+r)/2;
13         if(a[mid]<x) l=mid+1; else r=mid-1,k=mid;
14     }
15     return k;
16 }
17 int main()
18 {
19     int x1,x2,y1,y2;
20     scanf("%d",&n);
21     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
22     sort(a+1,a+n+1);
23     scanf("%d",&m);
24     for(int i=1;i<=m;i++)
25     {
26         scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
27         if((y1<0&&y2<0)||(y1>0&&y2>0))
28         {
29             printf("%d\n",abs(y1-y2)+abs(x1-x2));
30             continue;
31         }
32         if(x1>x2) swap(x1,x2);
33         int pos=find((x1+x2)/2);
34         if(a[pos]>=x1&&a[pos]<=x2 )printf("%d\n",abs(y1-y2)+abs(x1-x2));
35         else
36         {
37             int t1=abs(a[pos]-x1)+abs(a[pos]-x2)+abs(y1-y2),t2=0x7fffffff,t3=0x7fffffff;
38             if(pos>1) t2=abs(a[pos-1]-x1)+abs(a[pos-1]-x2)+abs(y1-y2);
39             if(pos<n) t3=abs(a[pos+1]-x1)+abs(a[pos+1]-x2)+abs(y1-y2);
40             if(t1>t2) t1=t2;
41             if(t1>t3) t1=t3;
42             printf("%d\n",t1);
43         }
44     }
45 }

原文地址:https://www.cnblogs.com/Comfortable/p/8427180.html

时间: 2024-10-12 22:05:14

[二分][排序] JZOJ P1792 教主的花园的相关文章

教主的花园

题目描述 教主最近总困扰于前来膜拜他的人太多了,所以他给他的花园加上了一道屏障. 可以把教主的花园附近区域抽像成一个正方形网格组成的网络,每个网格都对应了一个坐标(均为整数,有可能为负),若两个网格(x1, y1),(x2, y2)有|x1 - x2| + |y1 - y2| = 1,则说这两个网格是相邻的,否则不是相邻的. 教主在y = 0处整条直线上的网格设置了一道屏障,即所有坐标为(x, 0)的网格.当然,他还要解决他自己与内部人员的进出问题,这样教主设置了N个入口a1, a2, …, a

P1133 教主的花园

P1133 教主的花园 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高. 输入输出格式 输入格式: 输入文件garden.in的第1行为一个正整数n,表示需要种的树的

二分排序之三行代码

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include<stdio.h>  #include<stdlib.h>  int a[]={10,22,42,51,56,63,78,99,102,118};   int binSearch(int* a, int begin, int end, int k){      int mid = begin + ( (end - begin)>>1 ),index;      index

洛谷1133 教主的花园

洛谷1133 教主的花园 本题地址:http://www.luogu.org/problem/show?pid=1133 题目描述 教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值. 教主最喜欢3种树,这3种树的高度分别为10,20,30.教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最

POJ 2398 计算几何+二分+排序

Toy Storage Time Limit: 1000MS  Memory Limit: 65536K Total Submissions: 3953  Accepted: 2334 Description Mom and dad have a problem: their child, Reza, never puts his toys away when he is finished playing with them. They gave Reza a rectangular box t

洛谷P1133 教主的花园 动态规划

洛谷P1133 教主的花园动态规划 这里是环状的,但是我们并不用将他破环成链 只要枚举第一个点 根据第一个点选择最后一个选择什么就行了 然后我们进行DP注意如果当前是 2 的话要分情况 上一次是上升 1 还是下降 0 F1[ i ] 表示 第 i 位置的种第 1 种树所能获得的最大价值 F2[ i ][ 0 ] 表示 第 i 位置的 种第 2 种树 且上次是下降 1 #include <bits/stdc++.h> 2 #define For(i,j,k) for(int i=j;i<=

二分排序法

<pre> <script type="text/javascript"> //二分排序法从小到大排序 /*算法原理: 把一组数中的N个数分为三个部分: 第1部分.中间选一个 第2部分.小于中间的一个放左边 第3部分.大于中间的一个放到右边 重复以上步骤,直到排好为止.重复次数是不确定的根据元素多少和元素顺序都有关系 假设有数组: [7,6,9,5,3]; 第一次: 取出中间一项9,如果是偶数项比如4个可以取第二个或第三个都行的. 把小于9的放到左边数组中,大于

Codeforces Round #521 (Div. 3) D. Cutting Out 【二分+排序】

任意门:http://codeforces.com/contest/1077/problem/D D. Cutting Out time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standard output You are given an array ss consisting of nn integers. You have to find any ar

排序算法一二分排序

二分插入排序 简介 二分排序是指利用二分法的思想对插入排序进行改进的一种插入排序算法, 可以利用数组的特点快速定位指定索引的元素. 二分法排序的思想 必须是有序数组 在插入第i个元素时,对前面的0-i-1元素进行折半,先跟他们中间的那个元素比, 如果小,则对前半再进行折半,否则对后半进行折半,直到left>right,找到位置 然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上. 复杂度 二分排序的时间复杂度是O(logn), 空间复杂度O(1),是稳定排序. 1