SCOI2007 组队

传送门

这道题该怎么做呢……我自己只能想出来O(n^3)的暴力模拟……不过并不行。

来看一下正解吧……将给定的式子变一下形,得到A*height + B*speed - C <= A*minh+B*mins.

这样的话,把所有的运动员按照A*height + B*speed - C从小到大排序,这样就使得,如果有i成立,那么对于每个j<i,只要这个j的height和speed都不小于最小要求都是合法的。

但是不只有这一个限制。由于height还必须大于等于minh,所以对于任意一个运动员,其speed不仅要大于等于mins还要小于等于mins + C/B(这个用上面的式子可以推出)所以我们进行枚举,先枚举mins,之后再枚举minh,对于当前的minh,我们按照sum的顺序从小到大去枚举,如果这个运动员满足其speed >=mins && <= mins + C/B,那么这个运动员当前就是可以取的。这样我们维护了一个右区间,之后,我们再维护左区间,对于每一个height不够的运动员,我们把他从合法区间中踢出。不过有一些本身并没有被算过,所以只有对于s符合要求的那些,我们才会把其删除。这样每次在找完合法区间之后更新答案即可。

这种算法起到优化的作用在于其利用了单调性。我们来看,在从小到大枚举minh,mins的过程中,我们知道A*minh+B*mins.必然是单调递增的,也就是说,每次向后取一个元素,就会导致更多的人有被选中的机会。而对于已经被删除的人,因为我们枚举的最小高度肯定也是递增的,所以已经被删除的人将来也不可能合法。于是这个算法就用单调性来保证了它的正确性,同时完成了时间复杂度的优化。我们只需要O(2*n^2)的复杂度就可以过了。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define rep(i,a,n) for(ll i = a;i <= n;i++)
#define per(i,n,a) for(ll i = n;i >= a;i--)
#define enter putchar(‘\n‘)

using namespace std;
const int M = 5005;
typedef long long ll;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < ‘0‘ || ch > ‘9‘)
    {
        if(ch == ‘-‘) op = -1;
        ch = getchar();
    }
    while(ch >= ‘0‘ && ch <= ‘9‘)
    {
        ans *= 10;
        ans += ch - ‘0‘;
        ch = getchar();
    }
    return ans * op;
}

struct node
{
    int h,s,sum;
}Sum[M],H[M],S[M];
bool cmp1(node a,node b)
{
    return a.sum < b.sum;
}
bool cmp2(node a,node b)
{
    return a.h < b.h;
}
bool cmp3(node a,node b)
{
    return a.s < b.s;
}
int n,A,B,C,l,r,cnt,mins,lims,limsum,ans;

int main()
{
    n = read(),A = read(),B = read(),C = read();
    rep(i,1,n)
    {
        Sum[i].h = read(),Sum[i].s = read(),Sum[i].sum = Sum[i].h * A + Sum[i].s * B - C;
        H[i].h = Sum[i].h,H[i].s = Sum[i].s,H[i].sum = Sum[i].sum;
        S[i].h = Sum[i].h,S[i].s = Sum[i].s,S[i].sum = Sum[i].sum;
    }
    sort(Sum+1,Sum+1+n,cmp1);
    sort(H+1,H+1+n,cmp2);
    sort(S+1,S+1+n,cmp3);//上面是按照关键字排序
    rep(i,1,n)
    {
        l = 0,r = 0,cnt = 0;
        mins = S[i].s,lims = S[i].s + C / B;//确定限制范围
        rep(j,1,n)
        {
            limsum = A * H[j].h + B * mins;
            while(r < n && Sum[r+1].sum < limsum)
            {
                r++;
                if(mins <= Sum[r].s && Sum[r].s <= lims) cnt++;//将合法元素选中
            }//判断合法区间的末尾
            while(l < n && H[l+1].h < H[j].h)
            {
                l++;
                if(mins <= H[l].s && H[l].s <= lims) cnt--;
            }//判断合法区间开头并且删除不合法元素
            ans = max(ans,cnt);//更新答案
        }
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/captain1/p/9545399.html

时间: 2024-10-30 22:52:49

SCOI2007 组队的相关文章

BZOJ1071 [SCOI2007]组队

说好的一天一题解来啦~(其实是给马上要来的NOIP模拟赛加点RP>.<) Vfk大神说是n^2乱搞,于是蒟蒻就开始乱搞,结果发现怎么搞都是O(n ^ 3)的... 后来请教了snake大神,他说先给sum = A * h + B * s排序,然后枚举h和s的最小值.(h -- Height, s -- Speed) 然后就是两个指针乱搞: 先枚举s最小值,然后一边枚举v的最小值一边查询符合条件的人数,因为这一定是相邻的一串. 1 /*******************************

bzoj 1071: [SCOI2007]组队

Description NBA每年都有球员选秀环节.通常用速度和身高两项数据来衡量一个篮球运动员的基本素质.假如一支球队里 速度最慢的球员速度为minV,身高最矮的球员高度为minH,那么这支球队的所有队员都应该满足: A * ( height – minH ) + B * ( speed – minV ) <= C 其中A和B,C为给定的经验值.这个式子很容易理解,如果一个球队的 球员速度和身高差距太大,会造成配合的不协调. 请问作为球队管理层的你,在N名选秀球员中,最多能有多少名 符合条件的

【题解】SCOI2007组队

恩……为什么大家都这么执着于 \(O(n^{2})\) 的复杂度捏?如果接受 \(O(nV)\) 的复杂度,那这题可不是道**题吗( • ?ω•? )? 首先把所有的人按照身高排个序,然后我们就可以枚举一个人作为身高的最小值.此时,原式 \(A * H + B * V - C <= A * minh + B * minv\) 我们可以把常量固定一下: \(S_{x} = A * H_{x} - C - A * minh\) \(S_{x} + B * V_{x} <= B * minv\) 移

怒刷BZOJ记录(二)1038~10xx

我实在是太弱了...不滚粗只能刷BZOJ了...这里来记录每天刷了什么题吧. 2015-8-13: 正式开始! 1030[JSOI2007]文本生成器                       | ac自动机+DP 1042 [HAOI2008]硬币购物                        | 容斥原理+背包 1045 [HAOI2008] 糖果传递                       | 数学+中位数 1047 [HAOI2007]理想的正方形               

(双指针) bzoj 1071

1071: [SCOI2007]组队 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1267  Solved: 392[Submit][Status][Discuss] Description NBA每年都有球员选秀环节.通常用速度和身高两项数据来衡量一个篮球运动员的基本素质.假如一支球队里速度最慢的球员速度为minV,身高最矮的球员高度为minH,那么这支球队的所有队员都应该满足: A * ( height – minH ) + B * ( sp

【BZOJ1071】【SCOI2007】组队 利用单调性的双指针

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45746089"); } 题解: 三个定义:高度h,v速度,Ah+Bv为s 首先我们在外圈枚举来固定其中一个权值,姑且枚举v吧.每次枚举值大写为V. 然后在内圈就可以做单调队列了. 我们枚举让h递增,每次为H,然后发现原来的式子要满足

[SCOI2007]修车

1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 6007  Solved: 2559 [Submit][Status][Discuss] Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同 的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使得顾客平均等待的时间最 小. 说明:顾客的等待时间是指从他把车送至维修中心

1069: [SCOI2007]最大土地面积

1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 2961  Solved: 1162[Submit][Status][Discuss] Description 在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大. Input 第1行一个正整数N,接下来N行,每行2个数x,y,表示该点的横坐标和纵坐标. Output 最大的多边形面积,答案精确到

BZOJ1067: [SCOI2007]降雨量

1067: [SCOI2007]降雨量 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 4185  Solved: 1119[Submit][Status][Discuss] Description 我们常常会说这样的话:“X年是自Y年以来降雨量最多的”.它的含义是X年的降雨量不超过Y年,且对于任意Y<Z<X,Z年的降雨量严格小于X年.例如2002,2003,2004和2005年的降雨量分别为4920,5901,2832和3890,则可以说“200