【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,然后发现原来的式子要满足 Ah+Bv<=C+AH+BV 。

然后 H增大会使得右式增大,然后如果我们按s(定义去题解第一句话找)为键值从小到大排序,那么满足此式的队员是单调上升的。

然后 我们单调地每次把满足此式子的队员加入队列,判断如果其v值满足条件 V<=v<=V+CB ,则把它计数,即此种枚举情况时的ans++。( v<=V+CB 为什么对?如果 v>V+CB ,则 Bv?BV>C 然后你懂得)【加入环节】

然后 会有一些被计数的队员身高式子存在 h<H ,我们从前往后单调地把身高不满足上式的出队,如果之前被计数了,则此种枚举情况时的ans- -。【弹出环节】

这样比较一下这 n2 个答案,我们就在 O(n2) 的时间复杂度下解决了这道题。

但是?【弹出环节】是否会弹出一些【加入环节】没有加入的点呢?

让我来猜一猜,你的答案一定是”不会“吧?

然而答案是会,但是这种点并不会影响答案。

分类讨论下

首先如果一个点满足被计数的条件即 V<=v<=V+CB ,那么如果又满足 h<H 那么有 0+B(v?V)<=C ,而A(h?H)则一定<0 。

所以 A(h?H)+B(v?V)<=C 。。。。。。所以一定加进来然后被计数过,不会减多了。

然后如果不满足被计数的条件。23333,都没有被计数我们管它作甚?

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 5050
using namespace std;
int n,A,B,C;
int Max,Min,l,r,cnt,ans;
struct KSD
{
    int h,v,s;
    void keep(){s=A*h+B*v;}
}x[2][N];
inline bool cmph(const KSD &a,const KSD &b){return a.h<b.h;}
inline bool cmps(const KSD &a,const KSD &b){return a.s<b.s;}
inline bool check(int id,int d)
{return x[id][d].v<=Max&&x[id][d].v>=Min;}
int main()
{
    int i,j,k;
    scanf("%d%d%d%d",&n,&A,&B,&C);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&x[0][i].h,&x[0][i].v);
        x[0][i].keep(),x[1][i]=x[0][i];
    }
    sort(x[0]+1,x[0]+n+1,cmph);
    sort(x[1]+1,x[1]+n+1,cmps);
    for(i=1;i<=n;i++) // 枚举v最小值
    {
        Min=x[0][i].v,Max=Min+C/B;
        l=r=cnt=0;
        for(j=1;j<=n;j++) // 枚举h最小值
        {
            while(r<n&&x[1][r+1].s-A*x[0][j].h-B*x[0][i].v<=C)
                cnt+=check(1,++r);//按照s排序取出可行队员
            while(l<n&&x[0][l+1].h<x[0][j].h)cnt-=check(0,++l);
            ans=max(ans,cnt);//再干掉一些当初入队时计数了的队员
        }
    }
    printf("%d\n",ans);
    return 0;
}
时间: 2024-10-11 04:26:05

【BZOJ1071】【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 /*******************************

BZOJ1071 [SCOI2007]压缩 指针

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1071 题意概括 有两个序列a[1..n], b[1..n],其编号为1..n,设为s序列.现在我们要求出最长的满足条件的s的子序列s',设va=min(a[s[i]]), vb=min(b[s[i]]), 满足对于所有的j=s'[i], A*(a[j]-va)+B*(b[j]-vb)<=C. 题解 设v[i]=A*a[i]+B*b[i]; 那么,要求满足v[s'[i]]-A*va-B*vb<=

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,所以对于任意一个运动员,其s

bzoj 1071: [SCOI2007]组队

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

[hdu5358]分类统计,利用单调性优化

题意:直接来链接吧http://acm.hdu.edu.cn/showproblem.php?pid=5358 思路:注意S(i,j)具有区间连续性且单调,而⌊log2x⌋具有区间不变性,于是考虑枚举⌊log2S(i,j)⌋的值,然后枚举i,从而能得到j的区间范围,然后统计答案即可. 另外这题比较坑,先枚举 ⌊log2S(i,j)⌋再枚举i 老是TLE,加了各种常数优化还是TLE,换成先枚举i再枚举⌊log2S(i,j)⌋就过了. 1 2 3 4 5 6 7 8 9 10 11 12 13 14

【题解】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 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

ZOJ Monthly, January 2018

A. Candy Game 显然最优策略是一个一个吃,故比较哪种糖果的个数比较多即可. #include<cstdio> int T,n,i,x,sum; int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); sum=0; for(i=1;i<=n;i++)scanf("%d",&x),sum+=x; for(i=1;i<=n;i++)sca

一类分治问题

有一类关于区间最大值和最小值之类的问题,利用单调性,可以采用分治算法解决. SPOJ22343 Norma 题意,给定一个数列,定义区间的代价为区间最大值.区间最小值.区间长度的成绩,求所有区间的代价和. 既然是分治,我们肯定要处理一个数列跨过中点的答案. 假设当前数列的中点为mid,我们从mid往前扫,扫到了i. 然后根据单调性,我们越往左扫,最大值单调不降,最小值单调不增. 那么我们可以在右边维护一个指针,表示满足最大值的区间的最靠右的端点. 假设有这么一种情况,那么我们可以把区间拆成mid