4880: [Lydsy2017年5月月赛]排名的战争

4880: [Lydsy2017年5月月赛]排名的战争

Time Limit: 8 Sec Memory Limit: 256 MB
Submit: 265 Solved: 47
[Submit][Status][Discuss]
Description

小Q是一名出色的质检员,他负责质检一批手机的质量。手机包含两个性能属性:电池寿命x_1与坚硬度x_2。小Q将
为它们评估综合质量分数,具体地说,他将选择两个非负实数w_1,w_2,且$_1,w_2不能同时为0,则一部手机的综
合分数s=w_1*x_1+w_2*x_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

HINT

Source

鸣谢Claris上传试题

[Submit][Status][Discuss]

把问题转换一下
变成需要求最多有多少人分数更低,最少有多少人分数更低
把每个公司的手机的两个参数看成点 (x,y)
分数更优的条件就等价于 w1x1+w2y1w1x2+w2y2
移项得到 w1w2y2y1x2x1 w1w2y2y1x2x1
能满足一组 w1w2 的点恰好在同一个半平面
于是以一号手机为原点,其它点按照极角序排好,扫一遍就行了
边界上的点要特别提出来,因为评分相同的手机需要加上排名特技

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
 
typedef double DB;
typedef pair <DB,int> pr;
const int maxn = 2E5 + 20;
const DB _180 = acos(-1.00);
const DB _90 = _180 / 2.00;
const DB _360 = _180 * 2.00;
const DB EPS = 1E-10;
 
int n,X,Y,Max,Min = ~0U>>1,tot,c1,c2,cur = 1,sum[maxn];
DB ang[maxn],A[maxn];
pr p[maxn];
 
#define fr first
#define sc second
#define mp(a,b) (make_pair((a),(b)))
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
 
inline int fcmp(DB x)
{
    return fabs(x - _180) <= EPS ? 0 : (x < _180 ? -1 : 1);
}
 
inline int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}
 
int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif
     
    n = getint(); X = getint(); Y = getint();
    for (int i = 1; i < n; i++)
    {
        int x = getint(),y = getint();
        if (x > X && y > Y) continue;
        if (x < X && y < Y) {++c2; continue;}
        if (x == X && y == Y) {++c1; continue;}
        p[++tot] = mp(atan2(y - Y,x - X),1);
        if (p[tot].fr < 0 || fabs(p[tot].fr) <= EPS) p[tot].fr += _360;
        if (x >= X && y <= Y) p[++tot] = mp(atan2(y - Y,x - X) + _180,0);
    }
     
    sort(p + 1,p + tot + 1);
    for (int i = 2; i <= tot; i++)
        if (fabs(p[i].fr - p[i - 1].fr) <= EPS) p[cur].sc += p[i].sc;
        else p[++cur] = p[i];
    for (int i = 1; i <= cur; i++) sum[i] = p[i].sc + sum[i - 1];
    int pos = 1;
    for (int i = 1; i <= cur; i++)
    {
        if (fcmp(p[i].fr) == 1) break;
        while (pos < cur && fcmp(p[pos + 1].fr - p[i].fr) <= 0) ++pos;
        Max = max(Max,sum[pos] - sum[i - 1]);
        int now = sum[pos] - sum[i];
        if (fcmp(p[pos].fr - p[i].fr) == 0) now -= p[pos].sc;
        Min = min(Min,now);
    }
    printf("%d %d\n",n - Max - c1 - c2,n - Min - c2);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值