[Solution] 题解

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

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

#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();
}