• SCUT


    https://scut.online/p/484

    一开始想的是按固定斜率的直线从无穷扫下来,但是一直都WA,不知道是哪里错了还是精度问题?

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 1e5 + 5;
    
    int dcmp(long double x, long double y) {
        if(fabs(x - y) <= 1e-14)
            return 0;
        return x < y ? -1 : 1;
    }
    
    int n;
    ll q;
    
    int ch[MAXN][2];
    int val[MAXN];
    int dat[MAXN], siz[MAXN], cnt[MAXN];
    int tot, root;
    
    inline void Init() {
        tot = 0;
        root = 0;
    }
    
    inline int NewNode(int v) {
        val[++tot] = v, dat[tot] = rand();
        ch[tot][0] = ch[tot][1] = 0;
        siz[tot] = 1, cnt[tot] = 1;
        return tot;
    }
    
    inline void PushUp(int id) {
        siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
    }
    
    inline void Rotate(int &id, int d) {
        int temp = ch[id][d ^ 1];
        ch[id][d ^ 1] = ch[temp][d];
        ch[temp][d] = id;
        id = temp;
        PushUp(ch[id][d]), PushUp(id);
    }
    
    inline void Insert(int &id, int v) {
        if(!id)
            id = NewNode(v);
        else {
            if(v == val[id])
                ++cnt[id];
            else {
                int d = v < val[id] ? 0 : 1;
                Insert(ch[id][d], v);
                if(dat[id] < dat[ch[id][d]])
                    Rotate(id, d ^ 1);
            }
            PushUp(id);
        }
    }
    
    //找严格小于v的点的个数
    int GetRank(int id, int v) {
        if(!id)
            return 0;
        else {
            if(v == val[id])
                return siz[ch[id][0]];
            else if(v < val[id])
                return GetRank(ch[id][0], v);
            else
                return siz[ch[id][0]] + cnt[id] + GetRank(ch[id][1], v);
        }
    }
    
    const ll INF = 1e9;
    
    struct Point {
        long double x, y;
        Point() {}
        Point(long double x, long double y): x(x), y(y) {}
    
        Point Rotate(long double A) {
            return Point(x * cos(A) - y * sin(A), x * sin(A) + y * cos(A));
        }
    
        bool operator<(const Point &p)const {
            return (dcmp(x, p.x) != 0) ? (x < p.x) : (y < p.y);
        }
    
    
    } p[MAXN], p2[MAXN];
    
    int nxt[MAXN];
    
    bool check(ll k) {
        Init();
        long double A = atan2(1.0, 1.0 * k);
        for(int i = 1; i <= n; ++i)
            p2[i] = p[i].Rotate(A);
    
        //按斜率排序
        sort(p2 + 1, p2 + 1 + n);
    
        for(int i = 1; i <= n; ++i) {
            p2[i] = p2[i].Rotate(-A);
            p2[i].x = round(p2[i].x);
            p2[i].y = round(p2[i].y);
        }
    
        ll sum = 0;
        for(int i = 1; i <= n; ++i) {
            int res = GetRank(root, (int)p2[i].x);;
            sum += res;
            if(sum >= q)
                return true;
            Insert(root, (int)p2[i].x);
        }
        return false;
    }
    
    ll CASE() {
        scanf("%d%lld", &n, &q);
        long double maxy = -INF, miny = INF;
        for(int i = 1; i <= n; ++i) {
            cin>>p[i].x>>p[i].y;
            //scanf("%lf%lf", &p[i].x, &p[i].y);
            if(p[i].y > maxy)
                maxy = p[i].y;
            if(p[i].y < miny)
                miny = p[i].y;
        }
        ll L = -round(maxy - miny), R = round(maxy - miny), M;
        while(1) {
            M = (L + R) >> 1;
            if(L == M) {
                if(check(L))
                    return L;
                if(check(R))
                    return R;
                return INF;
            }
            if(check(M))
                R = M;
            else
                L = M + 1;
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int T;
        while(~scanf("%d", &T)) {
            while(T--) {
                ll res = CASE();
                if(res >= INF)
                    puts("INF");
                else
                    printf("%lld
    ", res);
            }
        }
        return 0;
    }
    

    事实上枚举斜率之后对式子变形:

    (frac{y_1-y_2}{x_1-x_2}<=k)

    不妨设x1>x2

    (y_1-y_2<=k(x_1-x_2))

    即:

    (y_1-kx_1<=y_2-kx_2)

    即满足 (x1>x2)(y_1-kx_1<=y_2-kx_2) 的数对的个数。lzf大佬说是逆序对,太强了。

    平衡树卡过去非常勉强:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 1e5 + 5;
    
    int n;
    ll q;
    
    int ch[MAXN][2];
    ll val[MAXN];
    int dat[MAXN], siz[MAXN], cnt[MAXN];
    int tot, root;
    
    inline void Init() {
        tot = 0;
        root = 0;
    }
    
    inline int NewNode(ll v) {
        val[++tot] = v, dat[tot] = rand();
        ch[tot][0] = ch[tot][1] = 0;
        siz[tot] = 1, cnt[tot] = 1;
        return tot;
    }
    
    inline void PushUp(int id) {
        siz[id] = siz[ch[id][0]] + siz[ch[id][1]] + cnt[id];
    }
    
    inline void Rotate(int &id, int d) {
        int temp = ch[id][d ^ 1];
        ch[id][d ^ 1] = ch[temp][d];
        ch[temp][d] = id;
        id = temp;
        PushUp(ch[id][d]), PushUp(id);
    }
    
    inline void Insert(int &id, ll v) {
        if(!id)
            id = NewNode(v);
        else {
            if(v == val[id])
                ++cnt[id];
            else {
                int d = v < val[id] ? 0 : 1;
                Insert(ch[id][d], v);
                if(dat[id] < dat[ch[id][d]])
                    Rotate(id, d ^ 1);
            }
            PushUp(id);
        }
    }
    
    int GetRank(int id, ll v) {
        if(!id)
            return 0;
        else {
            if(v == val[id])
                return siz[ch[id][1]] + cnt[id];
            else if(v < val[id])
                return siz[ch[id][1]] + cnt[id] + GetRank(ch[id][0], v);
            else
                return GetRank(ch[id][1], v);
        }
    }
    
    const int INF = 1e9;
    
    struct Point {
        int x, y;
        ll z;
        Point() {}
        Point(int x, int y): x(x), y(y) {}
    
        bool operator<(const Point &p)const {
            return (x != p.x) ? (x < p.x) : (y < p.y);
        }
    
    } p[MAXN];
    
    bool check(int k) {
        //printf("k=%d
    ", k);
        Init();
        for(int i = 1; i <= n; ++i) {
            p[i].z = 1ll * p[i].y - 1ll * k * p[i].x;
            //printf("p[%d].z=%lld%c", i, p[i].z, " 
    "[i == n]);
            //printf("p[%d].x=%d%c", i, p[i].x, " 
    "[i == n]);
        }
        ll sum = 0;
        for(int i = 1, nxt; i <= n; i = nxt) {
            for(nxt = i + 1; nxt <= n && p[nxt].x == p[i].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                //int gr = GetRank(root, p[j].z);
                //printf("j=%d ,gr=%d
    ", j, gr);
                sum += GetRank(root, p[j].z);
                //printf("sum=%lld
    ", sum);
    //            if(sum >= q)
    //                return true;
            }
            for(int j = i; j < nxt; ++j)
                Insert(root, p[j].z);
        }
        if(sum >= q)
            return true;
        return false;
    }
    
    int solve() {
        scanf("%d%lld", &n, &q);
        int maxy = -INF, miny = INF;
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d", &p[i].x, &p[i].y);
            if(p[i].y > maxy)
                maxy = p[i].y;
            if(p[i].y < miny)
                miny = p[i].y;
        }
        sort(p + 1, p + 1 + n);
        /*for(int i = 1; i <= n; ++i) {
           //p[i].z = 1ll * p[i].y - 1ll * k * p[i].x;
           //printf("p[%d].z=%lld%c", i, p[i].z, " 
    "[i == n]);
           printf("p[%d].x=%d%c", i, p[i].x, " 
    "[i == n]);
        }*/
        int L = -(maxy - miny), R = maxy - miny, M;
        while(1) {
            M = (L + R) >> 1;
            if(L == M) {
                if(check(L))
                    return L;
                if(check(R))
                    return R;
                return INF;
            }
            if(check(M))
                R = M;
            else
                L = M + 1;
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int T;
        while(~scanf("%d", &T)) {
            while(T--) {
                int res = solve();
                if(res >= INF)
                    puts("INF");
                else
                    printf("%d
    ", res);
            }
        }
        return 0;
    }
    

    求逆序对,用树状数组的话,是这样思考:把其中一维离散化,用树状数组来表示,按另一维顺序插入。
    下面是把z离散化,按x从小到大插入,那么每次合法的就是前面的比它小的x2里面z2>=z1的,这样就先求出<=z1-1的个数,然后用已经插入的数的个数i-1减去,这里要注意相同的x的处理,600ms:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 1e5 + 5;
    
    int n;
    ll q;
    
    int bit[MAXN];
    
    inline void Init() {
        memset(bit, 0, sizeof(bit[0]) * (n + 1));
    }
    
    inline int Sum(int x) {
        int res = 0;
        while(x) {
            res += bit[x];
            x -= x & -x;
        }
        return res;
    }
    
    inline void Add(int x, int v) {
        while(x <= n) {
            bit[x] += v;
            x += x & -x;
        }
    }
    
    struct Point {
        int x, y;
        ll z;
        Point() {}
        Point(int x, int y): x(x), y(y) {}
        bool operator<(const Point &p)const {
            return x < p.x;
        }
    } p[MAXN];
    
    ll pz[MAXN];
    
    bool check(int k) {
        Init();
        for(int i = 1; i <= n; ++i)
            pz[i] = p[i].z = 1ll * p[i].y - 1ll * k * p[i].x;
        sort(pz + 1, pz + 1 + n);
        int pzn = unique(pz + 1, pz + 1 + n) - (pz + 1);
        for(int i = 1; i <= n; ++i)
            p[i].z = lower_bound(pz + 1, pz + 1 + pzn, p[i].z) - pz;
        ll sum = 0;
        for(int i = 1, nxt; i <= n; i = nxt) {
            for(nxt = i + 1; nxt <= n && p[nxt].x == p[i].x; ++nxt);
            for(int j = i; j < nxt; ++j) {
                sum += ((ll)i - 1) - Sum(p[j].z - 1);
                if(sum >= q)
                    return true;
            }
            for(int j = i; j < nxt; ++j)
                Add(p[j].z, 1);
        }
        return false;
    }
    
    const int INF = 1e9;
    
    int solve() {
        scanf("%d%lld", &n, &q);
        int maxy = -INF, miny = INF;
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d", &p[i].x, &p[i].y);
            if(p[i].y > maxy)
                maxy = p[i].y;
            if(p[i].y < miny)
                miny = p[i].y;
        }
        sort(p + 1, p + 1 + n);
        int L = -(maxy - miny), R = maxy - miny, M;
        while(1) {
            M = (L + R) >> 1;
            if(L == M) {
                if(check(L))
                    return L;
                if(check(R))
                    return R;
                return INF;
            }
            if(check(M))
                R = M;
            else
                L = M + 1;
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int T;
        while(~scanf("%d", &T)) {
            while(T--) {
                int res = solve();
                if(res >= INF)
                    puts("INF");
                else
                    printf("%d
    ", res);
            }
        }
        return 0;
    }
    

    离散化x的话,会更快,300ms,毕竟不用每次都对z进行一次unique然后lowerbound,的确少了一半的常数。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 1e5 + 5;
    
    int n;
    ll q;
    
    int bit[MAXN];
    
    inline void Init() {
        memset(bit, 0, sizeof(bit[0]) * (n + 1));
    }
    
    inline int Sum(int x) {
        int res = 0;
        while(x) {
            res += bit[x];
            x -= x & -x;
        }
        return res;
    }
    
    inline void Add(int x) {
        while(x <= n) {
            ++bit[x];
            x += x & -x;
        }
    }
    
    struct Point {
        int x, y, idx;
        ll z;
        Point() {}
        Point(int x, int y): x(x), y(y) {}
        bool operator<(const Point &p)const {
            return z == p.z ? idx<p.idx: z > p.z;
        }
    } p[MAXN];
    
    int px[MAXN], pxn;
    
    bool check(int k) {
        Init();
        for(int i = 1; i <= n; ++i)
            p[i].z = p[i].y - 1ll * k * p[i].x;
        sort(p + 1, p + 1 + n);
        ll sum = 0;
        for(int i = 1; i <= n; ++i) {
            sum += Sum(p[i].idx - 1);
            if(sum >= q)
                return true;
            Add(p[i].idx);
        }
        return false;
    }
    
    const int INF = 1e9;
    
    int solve() {
        scanf("%d%lld", &n, &q);
        int maxy = -INF, miny = INF;
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d", &p[i].x, &p[i].y);
            px[i] = p[i].x;
            if(p[i].y > maxy)
                maxy = p[i].y;
            if(p[i].y < miny)
                miny = p[i].y;
        }
        sort(px + 1, px + 1 + n);
        pxn = unique(px + 1, px + 1 + n) - (px + 1);
        for(int i = 1; i <= n; ++i)
            p[i].idx = lower_bound(px + 1, px + 1 + pxn, p[i].x) - px;
        int L = miny - maxy, R = maxy - miny, M;
        while(1) {
            M = (L + R) >> 1;
            if(L == M) {
                if(check(L))
                    return L;
                if(check(R))
                    return R;
                return INF;
            }
            if(check(M))
                R = M;
            else
                L = M + 1;
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int T;
        while(~scanf("%d", &T)) {
            while(T--) {
                int res = solve();
                if(res >= INF)
                    puts("INF");
                else
                    printf("%d
    ", res);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    JobRunShell.cs not FOUND
    Manjaro Linux 更新后无法启动问题
    VMware Workstation 16 启动虚拟机失败(vmmon 版本问题)
    sql生成表模型字段
    【短道速滑六】古老的视频去噪算法(FLT_GradualNoise)解析并优化,可实现1920*1080 YUV数据400fps的处理能力。
    Mvc Redis 相关资料
    Android Handler内存泄露
    ANDROID中HANDLER使用浅析
    Android并发编程之白话文详解Future,FutureTask和Callable
    企业微信考勤接口返回的秒数与统计天数关系
  • 原文地址:https://www.cnblogs.com/Yinku/p/11337258.html
Copyright © 2020-2023  润新知