zoukankan      html  css  js  c++  java
  • Luogu P4479 [BJWC2018]第k大斜率

    一道清真简单的好写的题

    Luogu P4479


    题意

    求点集两两连出的直线中斜率第$ k$大的直线


    $ Solution$

    二分答案,设$x_j geq x_i$

    若点$ (x_i,y_i)$和点$(x_j,y_j)$构成的斜率大于二分的答案$ k$则有

    $ frac{y_j-y_i}{x_j-x_i} geq k$

    $y_j-k·x_j geq y_i-k·x_i$

    转化成二维偏序

    树状数组/归并排序维护即可

    注意特判各种边界问题

    时间复杂度$ O(n log^2 n)$


    $ my code$

    #include<ctime>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #define rt register int
    #define ll long long
    using namespace std;
    inline ll read(){
        ll x = 0; char zf = 1; char ch = getchar();
        while (ch != '-' && !isdigit(ch)) ch = getchar();
        if (ch == '-') zf = -1, ch = getchar();
        while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf;
    }
    void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);}
    void writeln(const ll y){write(y);putchar('
    ');}
    ll n,m;
    struct node{
        int x,y;
        bool operator <(const node s)const{
            if(x==s.x)return y>s.y;
            return x<s.x;
        }
    }a[100010];
    ll q[100010],zs[100010],ans;
    ll calc(int L,int R){
        if(L==R)return 0;
        if(ans>=m)return ans;
        const int mid=L+R>>1;
        calc(L,mid);calc(mid+1,R);if(ans>=m)return ans;
        for(rt i=mid+1,j=L;i<=R;i++){
            while(j<=mid&&q[j]<=q[i])j++;
            ans+=j-L;
        }
        int tot1=L,tot2=mid+1,pl=L;
        while(tot1<=mid||tot2<=R){
            if(tot1>mid||(q[tot1]>q[tot2]&&tot2<=R))zs[pl++]=q[tot2++];
            else zs[pl++]=q[tot1++];
        }
        for(rt i=L;i<=R;i++)q[i]=zs[i];
        return ans;
    }
    bool check(int x){
        ans=0;
        for(rt i=1;i<=n;i++)q[i]=(ll)a[i].y-(ll)x*a[i].x;
        return (calc(1,n)>=m);
    }
    int main(){
        n=read();m=read();
        for(rt i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
        sort(a+1,a+n+1);
        int L=-200000000,R=200000000;
        while(L<=R){
            const int mid=L+R>>1;
            if(check(mid))L=mid+1;
            else R=mid-1;
        }
        write(R);
        return 0;
    }
  • 相关阅读:
    MYSQL索引
    列表里重复次数最多的元素
    python学习笔记
    Spark 扫描 HDFS lzo/gz/orc异常压缩文件
    Yarn RM写ZNode超数据量限制bug修复
    Spark HistoryServer日志解析&清理异常
    【Yarn源码分析】Container启动流程源码分析
    Yarn NodeManager总体架构
    【Yarn源码分析】ApplicationMaster源码分析
    【Yarn源码分析】FairScheduler资源调度
  • 原文地址:https://www.cnblogs.com/DreamlessDreams/p/10083396.html
Copyright © 2011-2022 走看看