基准时间限制: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个数N,N为点的数量(0 <= N <= 50000)
第2 - N + 1行:N个点的坐标,坐标为整数。(0 <= X[i], Y[i] <= 10^9)
Output
输出斜率小于0的连线的数量。(2,3) (2,4)以及(2,3) (3,3)这2种情况不统计在内。
Input示例
4
2 3
3 4
1 5
4 6
Output示例
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的点对的数量
 
#include<queue>
#include<set>
#include<cstdio>
#include <iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define max_v 500005
struct node
{
int x,y;
int num;
} p[max_v];
bool cmp1(node a,node b)//树状数组操作需要
{
if(a.y!=b.y)
return a.y<b.y;
else
return a.x<b.x;
}
bool cmp2(node a,node b)//离散化需要
{
if(a.x!=b.x)
return a.x<b.x;
else
return a.y<b.y;
}
int c[max_v];
int maxx;
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int d)
{
while(x<=maxx)
{
c[x]+=d;
x+=lowbit(x);
}
}
int getsum(int x,int num)
{
int res=;
while(x>)
{
res+=c[x];
x-=lowbit(x);
}
return num-res;//当前点总数减去该点左下角点的数量就是右下角点的数量
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(c,,sizeof(c));
for(int i=; i<n; i++)
{
scanf("%d %d",&p[i].x,&p[i].y);
} //离散化
sort(p,p+n,cmp2);
int k=;
p[].num=k;
for(int i=; i<n; i++)
{
p[i].num=++k;
}
maxx=k; //树状数组
sort(p,p+n,cmp1);
long long ans=;
for(int i=; i<n; i++)
{
ans+=getsum(p[i].num,i);//注意是i,不是i+1,因为当前点总数不包括当前点自己
update(p[i].num,);
}
printf("%I64d\n",ans);
}
return ;
}
/*
题目意思:
问你斜率小于0的两点的有多少个 分析:
这题跟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的点对的数量 */

思路二:

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

从斜率的公式入手
(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个逆序数,
而小于等于的情况并不会产生。
#include<stdio.h>
#include<memory>
#include<algorithm>
using namespace std;
#define max_v 500005
typedef long long LL;
struct node
{
int x,y;
}p[max_v];
int a[max_v];
bool cmp(node a,node b)
{
if(a.x!=b.x)
return a.x<b.x;
else
return a.y<b.y;
}
int temp[max_v];
LL ans;
void mer(int s,int m,int t)
{
int i=s;
int j=m+;
int k=s;
while(i<=m&&j<=t)
{
if(a[i]<=a[j])
{
temp[k++]=a[i++];
}else
{
ans+=j-k;//求逆序数
temp[k++]=a[j++];
}
}
while(i<=m)
{
temp[k++]=a[i++];
}
while(j<=t)
{
temp[k++]=a[j++];
}
}
void cop(int s,int t)
{
for(int i=s;i<=t;i++)
a[i]=temp[i];
}
void megsort(int s,int t)
{
if(s<t)
{
int m=(s+t)/;
megsort(s,m);
megsort(m+,t);
mer(s,m,t);
cop(s,t);
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n==)
break;
ans=;
for(int i=;i<n;i++)
scanf("%d %d",&p[i].x,&p[i].y);
sort(p,p+n,cmp);
for(int i=;i<n;i++)
{
a[i]=p[i].y;
}
megsort(,n-);
printf("%lld\n",ans);
}
return ;
}
/*
从斜率的公式入手
(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个逆序数,
而小于等于的情况并不会产生。 */

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. BZOJ1856: [Scoi2010]字符串(组合数)

    题意 题目链接 Sol \(30 \%\)dp: \(f[i][j]\)表示放了\(i\)个\(1\)和\(j\)个\(0\)的不合法方案 f[0][0] = 1; cin >> N &g ...

  2. Django基础二之URL路由系统

    一 URL配置 Django 1.11版本 URLConf官方文档 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表.你就是以这 ...

  3. libevent2笔记(linux、windows、android的编译)

    0. 前言 我使用的版本是libevent-2.0.21-stable.高级的应用还是得看官网文档http://www.wangafu.net/~nickm/libevent-2.0/doxygen/ ...

  4. ubuntu禁止系统自动升级之界面操作

    ##第一步:首先找到System Settings,如下图所示: ##第二步:然后找到Solfware & Updates,如下图所示: ##第三步:点击Solfwate & Upda ...

  5. JavaWeb学习—思维导图

  6. android中的textview显示汉字不能自动换行的一个解决办法

    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_ ...

  7. node(4)express 框架 EJS模板,cookie, session的学习

    一.EJS 概述:前端咱们使用过的一个模板套路,是underscore的套路.接下来EJS它属于后台工程师人的模板. https://www.npmjs.com/package/ejs 官网地址 特点 ...

  8. python学习手册中的一些易忘的点(前三部分)

    1.ubuntu下让python脚本可直接运行: test.py文件(后缀可省)#!/usr/bin/pythonprint('wwwww') sudo chmod +x ./test.py (sud ...

  9. geogebra几何画图工具用法

    1. intersectPath :该命令可以自动“算出”对应多边形的交汇区域 2. 静态文本可以指定到一个对象的中间这样将来动态变化对象大小时也不出现问题 3.export worksheet 4. ...

  10. 设置Office 365邮箱默认发送和接收邮件大小限制

    Office 365默认的 35MB 的邮件大小限制.Office 365 最大是支持 150MB 的邮件体积的. 我们只需用 Windows Powershell 连接 Office 365 ,然后 ...