[Solution] 题解

发现蒟蒻如我实在是看不懂$guagua \ dalao$的旋转扫描线题解呀,而且似乎常数也较劣,蒟蒻我就写个基排解法水水题解。

看了下数据范围,发现$O(N^ 3 )$朴素算法似乎可过,交上去只过了第一个子任务,一看限制原来是爆记忆体了$orz$。
容易想到二分答案,$O(N^ 3 logV)$的时间无法接受,蒟蒻如我实在想不到比朴素$O(N^ 3 )$更优的$check$函数。
看到座标范围在$-1e6 \sim 1e6$间,代表答案$\le 4e12$,我们借助基排思想,即可以$O(N^ 3 )$的优秀复杂度通过此题,轻松拿下目前次优,实现细节详见代码,代码并不长。

#include <cstdio>
#include <cmath>
#include <cstring>

#define YZQ_orzorzorz
#define ll long long
#define rep(i,a,n) for(int i=a;i<n;i++)

const int mxn = 805,rdx = 1 << 21;struct node{int x,y;}pts[mxn]; // 储存点的结构体
int cnt[rdx]; // 基排用于统计数量的桶

// 快读快写

inline int read(){
    int ret=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        ret=(ret<<1)+(ret<<3)+(c^48);
        c=getchar();
    } return ret*f;
}
inline void write(ll a){
    if(a>9)write(a/10); 
    putchar(a%10+'0');
}

inline void mian(){
    int n=read(),K=read();rep(i,0,n)pts[i].x=read(),pts[i].y=read();
    rep(i,0,n)rep(j,i+1,n)rep(k,j+1,n)cnt[llabs((pts[j].x-pts[i].x)*1ll*(pts[k].y-pts[i].y)-(pts[k].x-pts[i].x)*1ll*(pts[j].y-pts[i].y))/rdx]++; // 先统计高位
    for(int id=0;id<rdx;K-=cnt[id++])if(K<=cnt[id]){ //找到答案所在的桶了
            memset(cnt,0,sizeof(cnt)); // 记得清零数组
            rep(i,0,n)rep(j,i+1,n)rep(k,j+1,n){
            ll v=llabs((pts[j].x-pts[i].x)*1ll*(pts[k].y-pts[i].y)-(pts[k].x-pts[i].x)*1ll*(pts[j].y-pts[i].y));
            if(v/rdx==id)cnt[v%rdx]++; // 高位和答案相同的才统计
        }
        for(int i=0;i<rdx;K-=cnt[i++])if(K<=cnt[i])return write(id*1ll*rdx+i); // 找到答案了,输出
    }
}

int main() {
        YZQ_orzorzorz
        mian();
}