[bzoj4880][几何][乱搞]排名的战争

55 篇文章 0 订阅
3 篇文章 0 订阅

Description

小Q是一名出色的质检员,他负责质检一批手机的质量。手机包含两个性能属性:电池寿命x_1与坚硬度x_2。小Q将
为它们评估综合质量分数,具体地说,他将选择两个非负实数w_1,w_2,且$_1,w_2不能同时为0,则一部手机的综
合分数s=w_1x_1+w_2x_2。在评定出所有手机的分数后,小Q会把手机按分数从高到低排序,若有多部手机分数相
同,他可以将它们随意排列,因此每部手机的排名都是独一无二的。聪明的你会发现,对于不同的w的选定,手机
的最终排名可能会大不一样。因此各个公司都会暗中贿赂小Q,希望他让自己的排名尽量靠前。现一共有n家公司,
每家公司提供了一部手机用于质检。tangjz知道小Q可以通过调参来控制排名,所以他想知道他的公司的手机排名 最高是多少,最低是多少。

Input

第一行包含一个正整数n(1<=n<=100000),即公司的个数。
接下来n行,每行两个正整数x_1,x_2(1<=x_1,x_2<=1000),分别表示每部手机的两个属性。
tangjz所在公司提供的手机总是输入里的第一部手机。

Output

输出一行两个整数,即最高排名与最低排名。

Sample Input

5

7 7

11 10

8 5

1 1

12 12

Sample Output

3 4

题解

根据平面向量的知识,我们可以把每个手机看作一个二维点 ( x i , y i ) (x_i,y_i) (xi,yi)
对于需要确定的两个参数,可以看作 ( w 1 , w 2 ) (w_1,w_2) (w1,w2)
那一个手机的分数就相当于两个向量相乘了
向量相乘还有另外一种定义,就是在某个向量上的投影乘这个向量的长度
显然我们把所有向量投影到这个 ( w 1 , w 2 ) (w_1,w_2) (w1,w2)的向量上比较大小就可以知道排名了
回到本题
发现对于第一个手机,严格在左下方和严格在右上方的点都是无效的
要不就一直比他小要不就一直比他大
只用考虑在左上方和右下方的点
枚举一个点,可以发现,使得1号点比这个点优秀的 w w w向量在斜率方面是一个连续的范围
反之也是一个连续的范围
对于左上方的点,把他和1号点作一条直线并取这条直线的垂线,不难只有 w w w向量在垂线的下方才能使得1号点比这个点优秀,取补集即为这个点比1号点优秀
右下方的点把上面的向量反过来就是同理的
于是处理出来这个就可以了…
最后可以差分一遍然后扫过去处理答案
注意要判掉斜率相等的情况,以及 Y Y Y相同的情况
Y Y Y相同的时候显然此时斜率为正无穷
X X X相同就不管了
我写的这么详细不给个好评吗…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(LL x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=100005;
struct line{double K;int c;}w[MAXN];int tot;
bool cmp(line n1,line n2){return n1.K>n2.K;}
int X[MAXN],Y[MAXN],n,base1,gg,base2;
int s[MAXN];
int main()
{
	n=read();
	for(int i=1;i<=n;i++)X[i]=read(),Y[i]=read();
	for(int i=2;i<=n;i++)
	{
		if(X[i]==X[1]&&Y[i]==Y[1]){gg++;continue;}
		if(X[i]>X[1]&&Y[i]>Y[1]){base1++;continue;}
		if(X[i]<X[1]&&Y[i]<Y[1]){base2++;continue;}
		if(Y[1]!=Y[i])
		{
			double K1=(double)(X[1]-X[i])/(Y[1]-Y[i]);
			tot++;
			w[tot].K=-1.0*K1;
			if(X[i]<=X[1]&&Y[i]>=Y[1])w[tot].c=-1;
			else w[tot].c=1;
		}
		else 
		{
			tot++;w[tot].K=999999999;
			if(X[i]<=X[1])w[tot].c=-1;
			else w[tot].c=1;
		}
	}
	//-1 在下面  1  在上面
	sort(w+1,w+1+tot,cmp); 
	int lst=1;
	for(int i=1;i<=tot;i++)
	{
		if(w[i].K!=w[i-1].K)lst=i;
		if(w[i].c<0)
		{
			s[lst]++,s[tot+1]--;
		}
		else s[1]++,s[i+1]--;
	}
	int a1=0;
	for(int i=1;i<=tot;i++)s[i]+=s[i-1],a1=max(a1,s[i]);
	pr1(n-(a1+base2+gg));
	memset(s,0,sizeof(s));
	
	lst=1;
	for(int i=1;i<=tot;i++)
	{
		if(w[i].K!=w[i-1].K)lst=i;
		if(w[i].c>0)
		{
			s[lst]++,s[tot+1]--;
		}
		else s[1]++,s[i+1]--;
	}
	int a2=0;
	for(int i=1;i<=tot;i++)s[i]+=s[i-1],a2=max(a2,s[i]);
	pr2(a2+gg+base1+1);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值