基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 
二维平面上N个点之间共有C(n,2)条连线。求这C(n,2)条线中斜率小于0的线的数量。
二维平面上的一个点,根据对应的X Y坐标可以表示为(X,Y)。例如:(2,3) (3,4) (1,5) (4,6),其中(1,5)同(2,3)(3,4)的连线斜率 < 0,因此斜率小于0的连线数量为2。
 
Input
  1. 1行:1个数NN为点的数量(0 <= N <= 50000)
  2. 2 - N + 1行:N个点的坐标,坐标为整数。(0 <= X[i], Y[i] <= 10^9)
Output
  1. 输出斜率小于0的连线的数量。(2,3) (2,4)以及(2,3) (3,3)这2种情况不统计在内。
Input示例
  1. 4
  2. 2 3
  3. 3 4
  4. 1 5
  5. 4 6
Output示例
  1. 2
李陶冶 (题目提供者)

题目意思:
问你斜率小于0的两点的有多少个
分析:
方法1:直接树状数组求解
这题跟poj 2352很相像
那题是求某个点左下角点的个数,本题是求某个点左上角点的个数
那题输入是由规则的(按照y的升序,y相等的话,x小的在前)
所以这题一开始也要按照这个规则先排一下序
如果我们直接求某个点左上角的点的个数的话,直接改一下那题就可以了,但是有一点麻烦的地方:
那个题处于做下角边界的情况也是统计在内的
但是这题不行
所以有点麻烦
但是我们可以转化一下思路
因为一开始按照那个排序规则是已经排好序了的
所以当前点肯定是y最大的点,那么以该点为分界点
和该点斜率大于等于0或者斜列不存在的点肯定都是位于该点的左下角的
那么这个时候所有点的数量(不包括当前点)减去当前点左下角的点的数量(包括左下角的边界)
就是斜率小于0的点的数量
即就是该点右下角点的数量(不包括边界的,边界的前面左下角算过了)
还有一个问题就是数据太大了,c数组开不了,需要离散化
所以
先将输入的数据按照x离散化一下,因为每次getsum都是传x进去的
具体操作:
数据先按照x升序,x相等则y小的放前面的规则排序
因为每次getsum都是传x进去,所以按照x优先的规则排序好
排序好之后给按照顺序给点一个编号
这个就是所谓的离散化
然后getsum传进去的就是编号
具体理解一下,编号间的大小顺序关系和x原来的大小顺序关系是一样的
只是数据的范围被压缩了,但是期间各个数据的关系是没有变的
所以是可以这样的
这个就是离散化
离散化完成之后
就是跟star那题差不多了,按照y升序,y相等则x小的放前面的规则排序
然后每次getsum的时候得到的是左下角点的数量
当前点总数(除当前点)减去当前点左下角点的数量
就是当前点右下角的数量
就是和当前点斜率小于0的点的数量
然后将每次getsum的答案加起来就是所有斜率小于0的点对的数量
 
  1. #include<queue>
  2. #include<set>
  3. #include<cstdio>
  4. #include <iostream>
  5. #include<algorithm>
  6. #include<cstring>
  7. #include<cmath>
  8. using namespace std;
  9. #define max_v 500005
  10. struct node
  11. {
  12. int x,y;
  13. int num;
  14. } p[max_v];
  15. bool cmp1(node a,node b)//树状数组操作需要
  16. {
  17. if(a.y!=b.y)
  18. return a.y<b.y;
  19. else
  20. return a.x<b.x;
  21. }
  22. bool cmp2(node a,node b)//离散化需要
  23. {
  24. if(a.x!=b.x)
  25. return a.x<b.x;
  26. else
  27. return a.y<b.y;
  28. }
  29. int c[max_v];
  30. int maxx;
  31. int lowbit(int x)
  32. {
  33. return x&(-x);
  34. }
  35. void update(int x,int d)
  36. {
  37. while(x<=maxx)
  38. {
  39. c[x]+=d;
  40. x+=lowbit(x);
  41. }
  42. }
  43. int getsum(int x,int num)
  44. {
  45. int res=;
  46. while(x>)
  47. {
  48. res+=c[x];
  49. x-=lowbit(x);
  50. }
  51. return num-res;//当前点总数减去该点左下角点的数量就是右下角点的数量
  52. }
  53. int main()
  54. {
  55. int n;
  56. while(~scanf("%d",&n))
  57. {
  58. memset(c,,sizeof(c));
  59. for(int i=; i<n; i++)
  60. {
  61. scanf("%d %d",&p[i].x,&p[i].y);
  62. }
  63.  
  64. //离散化
  65. sort(p,p+n,cmp2);
  66. int k=;
  67. p[].num=k;
  68. for(int i=; i<n; i++)
  69. {
  70. p[i].num=++k;
  71. }
  72. maxx=k;
  73.  
  74. //树状数组
  75. sort(p,p+n,cmp1);
  76. long long ans=;
  77. for(int i=; i<n; i++)
  78. {
  79. ans+=getsum(p[i].num,i);//注意是i,不是i+1,因为当前点总数不包括当前点自己
  80. update(p[i].num,);
  81. }
  82. printf("%I64d\n",ans);
  83. }
  84. return ;
  85. }
  86. /*
  87. 题目意思:
  88. 问你斜率小于0的两点的有多少个
  89.  
  90. 分析:
  91. 这题跟poj 2352很相像
  92. 那题是求某个点左下角点的个数,本题是求某个点左上角点的个数
  93. 那题输入是由规则的(按照y的升序,y相等的话,x小的在前)
  94. 所以这题一开始也要按照这个规则先排一下序
  95. 如果我们直接求某个点左上角的点的个数的话,直接改一下那题就可以了,但是有一点麻烦的地方:
  96. 那个题处于做下角边界的情况也是统计在内的
  97. 但是这题不行
  98. 所以有点麻烦
  99. 但是我们可以转化一下思路
  100. 因为一开始按照那个排序规则是已经排好序了的
  101. 所以当前点肯定是y最大的点,那么以该点为分界点
  102. 和该点斜率大于等于0或者斜列不存在的点肯定都是位于该点的左下角的
  103. 那么这个时候所有点的数量(不包括当前点)减去当前点左下角的点的数量(包括左下角的边界)
  104. 就是斜率小于0的点的数量
  105. 即就是该点右下角点的数量(不包括边界的,边界的前面左下角算过了)
  106.  
  107. 还有一个问题就是数据太大了,c数组开不了,需要离散化
  108. 所以
  109. 先将输入的数据按照x离散化一下,因为每次getsum都是传x进去的
  110. 具体操作:
  111. 数据先按照x升序,x相等则y小的放前面的规则排序
  112. 因为每次getsum都是传x进去,所以按照x优先的规则排序好
  113. 排序好之后给按照顺序给点一个编号
  114. 这个就是所谓的离散化
  115. 然后getsum传进去的就是编号
  116. 具体理解一下,编号间的大小顺序关系和x原来的大小顺序关系是一样的
  117. 只是数据的范围被压缩了,但是期间各个数据的关系是没有变的
  118. 所以是可以这样的
  119. 这个就是离散化
  120.  
  121. 离散化完成之后
  122. 就是跟star那题差不多了,按照y升序,y相等则x小的放前面的规则排序
  123. 然后每次getsum的时候得到的是左下角点的数量
  124. 当前点总数(除当前点)减去当前点左下角点的数量
  125. 就是当前点右下角的数量
  126. 就是和当前点斜率小于0的点的数量
  127. 然后将每次getsum的答案加起来就是所有斜率小于0的点对的数量
  128.  
  129. */

思路二:

转换为求逆序数,然后归并求逆序

从斜率的公式入手
(xi-xj)/(yi-yj)<0 的点对的个数
现在我们先按照x升序,x相同的则y小的放前面规则排好序
假设i<j
那么xi-xj肯定是小于0的
那么斜率要求小于0,则要求yi-yj大于0
则就是求排好序之后所有的y组成的序列的逆序数
它的逆序数就是斜率小于0点对的个数!
所以先按照那个规则排好序
然后将y拿出来组成一个数组
用归并排序求数列的逆序数
归并可以求逆序的理由:
在归并排序的过程中,比较关键的是通过递归,
将两个已经排好序的数组合并,
此时,若a[i] > a[j],则i到m之间的数都大于a[j],
合并时a[j]插到了a[i]之前,此时也就产生的m-i+1个逆序数,
而小于等于的情况并不会产生。
  1. #include<stdio.h>
  2. #include<memory>
  3. #include<algorithm>
  4. using namespace std;
  5. #define max_v 500005
  6. typedef long long LL;
  7. struct node
  8. {
  9. int x,y;
  10. }p[max_v];
  11. int a[max_v];
  12. bool cmp(node a,node b)
  13. {
  14. if(a.x!=b.x)
  15. return a.x<b.x;
  16. else
  17. return a.y<b.y;
  18. }
  19. int temp[max_v];
  20. LL ans;
  21. void mer(int s,int m,int t)
  22. {
  23. int i=s;
  24. int j=m+;
  25. int k=s;
  26. while(i<=m&&j<=t)
  27. {
  28. if(a[i]<=a[j])
  29. {
  30. temp[k++]=a[i++];
  31. }else
  32. {
  33. ans+=j-k;//求逆序数
  34. temp[k++]=a[j++];
  35. }
  36. }
  37. while(i<=m)
  38. {
  39. temp[k++]=a[i++];
  40. }
  41. while(j<=t)
  42. {
  43. temp[k++]=a[j++];
  44. }
  45. }
  46. void cop(int s,int t)
  47. {
  48. for(int i=s;i<=t;i++)
  49. a[i]=temp[i];
  50. }
  51. void megsort(int s,int t)
  52. {
  53. if(s<t)
  54. {
  55. int m=(s+t)/;
  56. megsort(s,m);
  57. megsort(m+,t);
  58. mer(s,m,t);
  59. cop(s,t);
  60. }
  61. }
  62. int main()
  63. {
  64. int n;
  65. while(~scanf("%d",&n))
  66. {
  67. if(n==)
  68. break;
  69. ans=;
  70. for(int i=;i<n;i++)
  71. scanf("%d %d",&p[i].x,&p[i].y);
  72. sort(p,p+n,cmp);
  73. for(int i=;i<n;i++)
  74. {
  75. a[i]=p[i].y;
  76. }
  77. megsort(,n-);
  78. printf("%lld\n",ans);
  79. }
  80. return ;
  81. }
  82. /*
  83. 从斜率的公式入手
  84. (xi-xj)/(yi-yj)<0 的点对的个数
  85. 现在我们先按照x升序,x相同的则y小的放前面规则排好序
  86. 假设i<j
  87. 那么xi-xj肯定是小于0的
  88. 那么斜率要求小于0,则要求yi-yj大于0
  89. 则就是求排好序之后所有的y组成的序列的逆序数
  90. 它的逆序数就是斜率小于0点对的个数!
  91. 所以先按照那个规则排好序
  92. 然后将y拿出来组成一个数组
  93. 用归并排序求数列的逆序数
  94. 归并可以求逆序的理由:
  95.  
  96. 在归并排序的过程中,比较关键的是通过递归,
  97. 将两个已经排好序的数组合并,
  98. 此时,若a[i] > a[j],则i到m之间的数都大于a[j],
  99. 合并时a[j]插到了a[i]之前,此时也就产生的m-i+1个逆序数,
  100. 而小于等于的情况并不会产生。
  101.  
  102. */

51 Nod 1107 斜率小于0的连线数量 (转换为归并求逆序数或者直接树状数组,超级详细题解!!!)的更多相关文章

  1. 51Nod - 1107 斜率小于0的连线数量

    二维平面上N个点之间共有C(n,2)条连线.求这C(n,2)条线中斜率小于0的线的数量. 二维平面上的一个点,根据对应的X Y坐标可以表示为(X,Y).例如:(2,3) (3,4) (1,5) (4, ...

  2. 51NOD——N 1107 斜率小于0的连线数量

    https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1107 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 ...

  3. 剑指 Offer 51. 数组中的逆序对 + 归并排序 + 树状数组

    剑指 Offer 51. 数组中的逆序对 Offer_51 题目描述 方法一:暴力法(双层循环,超时) package com.walegarrett.offer; /** * @Author Wal ...

  4. [luogu4479][BJWC2018]第k大斜率【二维偏序+二分+离散化+树状数组】

    传送门 https://www.luogu.org/problemnew/show/P4479 题目描述 在平面直角坐标系上,有 n 个不同的点.任意两个不同的点确定了一条直线.请求出所有斜率存在的直 ...

  5. NOI.AC#2139-选择【斜率优化dp,树状数组】

    正题 题目链接:http://noi.ac/problem/2139 题目大意 给出\(n\)个数字的序列\(a_i\).然后选出一个不降子序列最大化子序列的\(a_i\)和减去没有任何一个数被选中的 ...

  6. CF E. Vasya and a Tree】 dfs+树状数组(给你一棵n个节点的树,每个点有一个权值,初始全为0,m次操作,每次三个数(v, d, x)表示只考虑以v为根的子树,将所有与v点距离小于等于d的点权值全部加上x,求所有操作完毕后,所有节点的值)

    题意: 给你一棵n个节点的树,每个点有一个权值,初始全为0,m次操作,每次三个数(v, d, x)表示只考虑以v为根的子树,将所有与v点距离小于等于d的点权值全部加上x,求所有操作完毕后,所有节点的值 ...

  7. 51nod 1107 斜率小于零连线数量 特调逆序数

    逆序数的神题.... 居然是逆序数 居然用逆序数过的 提示...按照X从小到大排列,之后统计Y的逆序数... 之后,得到的答案就是传说中的解(斜率小于零) #include<bits/stdc+ ...

  8. UVa 11384 - Help is needed for Dexter 分析, 树状数组 难度: 0

    题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...

  9. 51 Nod 1100 斜率最大

    1100 斜率最大  基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  关注 平面上有N个点,任意2个点确定一条直线,求出所有这些直线中,斜率最大的那条直线 ...

随机推荐

  1. JS判断客户端是否是iOS或者Android端

    通过判断浏览器的userAgent,用正则来判断手机是否是 IOS 和 Android 客户端. 代码如下: (function(){ var u = navigator.userAgent; var ...

  2. flutter Row里面元素居中显示

    直接上代码: new Expanded( flex: , child: new Row( children: <Widget>[ Expanded( child: new Containe ...

  3. android--Git上克隆项目遇到的坑

    直接上图,首先你得有你得GitHub项目地址,如下: 然后打开android studio,选择新建项目时从Git上克隆: 点击clone等待完成,新窗口打开. 打开之后可能.或许.大概.也许会出现下 ...

  4. Android横、竖屏幕动态切换(layout-land 和layout-port)

    下面是一个例子程序: 1.首先通过以下语句设置Activity为无标题和全屏模式: // 设置为无标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE); ...

  5. maven 超级pom位置、maven命令、构件、下载位置、手动打包位置、中央仓库ip

    1.超级pom位置 ----> 解压M2_HOME/lib/maven-model-builder-3.5.4.jar 2.运行maven 命令实际上是运行了 java 命令,因为maven插件 ...

  6. win7安装node.js

    最新版本的node.js都已经集成了npm,所以直接从官网下载即可!(不用再配置环境变量) 官网:https://nodejs.org/download/release/latest/ 下载解压即安装 ...

  7. Oracle EBS 清除并发请求和(或)管理器数据 请求

    请求说明:该请求可以清除平时提交的请求日志文件.并发管理器的日志文件.报表输出文件.并发请求和并发管理器进程的历史记录信息. 参数说明:(红色标注字段为必输项)1.  实体:ALL:清除请求历史记录. ...

  8. SQL SERVER Management Studio编写SQL时没有智能提示的解决方式

    1. 检查设置里是否启用智能感知(Intellisence),可以在“工具”→“选项”里设置 2. 如果启用后还是无效,可以新建一个查询窗口查询,输入关键词的前面几个字母看是否有提示(或者使用Ctrl ...

  9. 细说C#继承

    简介 继承(封装.多态)是面向对象编程三大特性之一,继承的思想就是摈弃代码的冗余,实现更好的重用性. 继承从字面上理解,无外乎让人想到某人继承某人的某些东西,一个给一个拿.这个语义在生活中,就像 家族 ...

  10. sql面试

    1.用一条SQL语句 查询出每门课都大于80分的学生姓名 name   kecheng   fenshu 张三     语文       81张三     数学       75李四     语文   ...