[bzoj4880][幾何][亂搞]排名的戰爭

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

題解

根據平面向量的知識,我們可以把每個手機看作一個二維點(xi,yi)(x_i,y_i)
對於需要確定的兩個參數,可以看作(w1,w2)(w_1,w_2)
那一個手機的分數就相當於兩個向量相乘了
向量相乘還有另外一種定義,就是在某個向量上的投影乘這個向量的長度
顯然我們把所有向量投影到這個(w1,w2)(w_1,w_2)的向量上比較大小就可以知道排名了
回到本題
發現對於第一個手機,嚴格在左下方和嚴格在右上方的點都是無效的
要不就一直比他小要不就一直比他大
只用考慮在左上方和右下方的點
枚舉一個點,可以發現,使得1號點比這個點優秀的ww向量在斜率方面是一個連續的範圍
反之也是一個連續的範圍
對於左上方的點,把他和1號點作一條直線並取這條直線的垂線,不難只有ww向量在垂線的下方纔能使得1號點比這個點優秀,取補集即爲這個點比1號點優秀
右下方的點把上面的向量反過來就是同理的
於是處理出來這個就可以了…
最後可以差分一遍然後掃過去處理答案
注意要判掉斜率相等的情況,以及YY相同的情況
YY相同的時候顯然此時斜率爲正無窮
XX相同就不管了
我寫的這麼詳細不給個好評嗎…

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章