zoukankan      html  css  js  c++  java
  • 极角排序

    1. gym102465F

    题意:给定$n$个有权值的平面点,求选两点连线,使得直线两边权值和差最小

    思路就是枚举每个点极角排序,滑动区间维护长π的区间的权值和

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 4e3+10;
    const double pi = acos(-1);
    struct point {
        int x,y,z;
    } a[N];
    pair<double,int> b[N*2];
    int main() {
        int n;
        scanf("%d", &n);
        int64_t sum = 0;
        for (int i=1; i<=n; ++i) { 
            scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z);
            sum += a[i].z;
        }
        int64_t ans = sum;
        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=n; ++j) if (i!=j) {
                b[j-(i<j)] = {atan2(a[j].y-a[i].y,a[j].x-a[i].x),a[j].z};
            }
            sort(b+1,b+n);
            for (int j=1; j<n; ++j) b[j+n-1] = {b[j].first+2*pi,b[j].second};
            int now = 1;
            int64_t w = 0;
            for (int j=1; j<n; ++j) {
                while (now<=2*n-2&&b[now].first-b[j].first<pi) w += b[now++].second;
                ans = min(ans, abs((w-b[j].second)-(sum-a[i].z-w)));
                w -= b[j].second;
            }
        }
        printf("%lld
    ", ans);
    }
    按atan2排序
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 4e3+10;
    const double pi = acos(-1);
    struct point {
        int x,y,z,tp;
        bool operator < (const point & b) const {
            if (tp!=b.tp) return tp<b.tp;
            return y*(int64_t)b.x<x*(int64_t)b.y;
        }
    } a[N],b[N*2];
    int get(int x, int y) {
        if (x>0&&y>=0) return 1;
        if (x<=0&&y>0) return 2;
        if (x<0&&y<=0) return 3;
        return 4;
    }
    int main() {
        int n;
        scanf("%d", &n);
        int64_t sum = 0;
        for (int i=1; i<=n; ++i) { 
            scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z);
            sum += a[i].z;
        }
        int64_t ans = sum;
        for (int i=1; i<=n; ++i) {
            int tot = 0;
            for (int j=1; j<=n; ++j) if (i!=j) { 
                ++tot;
                b[tot] = {a[j].x-a[i].x,a[j].y-a[i].y,a[j].z};
                b[tot].tp = get(b[tot].x,b[tot].y);
            }
            sort(b+1,b+tot+1);
            for (int j=1; j<n; ++j) ++tot, b[tot] = b[j], b[tot].tp += 4;
            int now = 1;
            int64_t w = 0;
            for (int j=1; j<n; ++j) {
                point u{-b[j].x,-b[j].y,b[j].z,b[j].tp+2};
                while (now<=tot&&b[now]<u) w += b[now++].z;
                ans = min(ans, abs((w-b[j].z)-(sum-a[i].z-w)));
                w -= b[j].z;
            }
        }
        printf("%lld
    ", ans);
    }
    按叉积排序

    2. gym102361A

    题意:给定$n$个点$P_i$,$q$个询问,给定点$A_i$,求多少二元组$(u,v)$,满足$A_i,P_u,P_v$为直角三角形

    按每个询问点极角排序,可以求出询问点为直角顶点的答案。然后离线按每个给定点极角排序,求出每个询问点为锐角顶点的答案

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 4e3+10;
    struct point {
        int x,y,tp;
        bool operator < (const point & b) const {
            if (tp!=b.tp) return tp<b.tp;
            return y*(int64_t)b.x<x*(int64_t)b.y;
        }
        bool operator <= (const point &b) const {
            return !(b<*this);
        }
    } a[N],b[N],f[N*2];
    pair<point,int> g[N];
    int ans[N];
    int get(int x, int y) {
        if (x>0&&y>=0) return 1;
        if (x<=0&&y>0) return 2;
        if (x<0&&y<=0) return 3;
        return 4;
    }
    int main() {
        int n, q;
        scanf("%d%d", &n, &q);
        for (int i=1; i<=n; ++i) scanf("%d%d", &a[i].x, &a[i].y);
        for (int i=1; i<=q; ++i) { 
            scanf("%d%d", &b[i].x, &b[i].y);
            for (int j=1; j<=n; ++j) {
                f[j] = {a[j].x-b[i].x,a[j].y-b[i].y};
                f[j].tp = get(f[j].x,f[j].y);
            }
            sort(f+1,f+1+n);
            for (int j=1; j<=n; ++j) f[j+n] = f[j], f[j+n].tp += 4;
            int lx = 1, rx = 1;
            for (int j=1; j<=n; ++j) {
                point u{-f[j].y,f[j].x,f[j].tp+1};
                while (lx<=2*n&&f[lx]<u) ++lx;
                while (rx<=2*n&&f[rx]<=u) ++rx;
                ans[i] += rx-lx;
            }
        }
        for (int i=1; i<=n; ++i) {
            int tot = 0;
            for (int j=1; j<=n; ++j) if (i!=j) {
                f[++tot] = {a[j].x-a[i].x,a[j].y-a[i].y};
                f[tot].tp = get(f[tot].x,f[tot].y);
            }
            sort(f+1,f+1+tot);
            for (int j=1; j<n; ++j) ++tot, f[tot] = f[j], f[tot].tp += 4;
            for (int j=1; j<=q; ++j) { 
                g[j].first = {b[j].x-a[i].x,b[j].y-a[i].y};
                g[j].first.tp = get(g[j].first.x,g[j].first.y);
                g[j].second = j;
            }
            sort(g+1,g+1+q);
            int lx = 1, rx = 1;
            for (int j=1; j<=q; ++j) {
                point v{-g[j].first.y,g[j].first.x,g[j].first.tp+1};
                while (lx<=tot&&f[lx]<v) ++lx;
                while (rx<=tot&&f[rx]<=v) ++rx;
                ans[g[j].second] += rx-lx;
            }
            lx = rx = tot;
            for (int j=q; j; --j) {
                point v{g[j].first.y,-g[j].first.x,g[j].first.tp-1+4};
                while (lx>=1&&v<f[lx]) --lx;
                while (rx>=1&&v<=f[rx]) --rx;
                ans[g[j].second] += lx-rx;
            }
        }
        for (int i=1; i<=q; ++i) printf("%d
    ", ans[i]);
    }
    View Code

    因为只用求直角,可以不极角排序,直接把向量reduce后判断

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e3+10;
    int n, q;
    struct point {
        int x, y;
    } a[N], b[N];
    pair<int,int> f[N];
    int ans[N];
    int gcd(int x, int y) {return y?gcd(y,x%y):x;}
    pair<int,int> reduce(int x, int y) {
        int g = gcd(abs(x),abs(y));
        if (g) x /= g, y /= g;
        return pair<int,int>(x,y);
    }
    int main() {
        scanf("%d%d", &n, &q);
        for (int i=1; i<=n; ++i) scanf("%d%d", &a[i].x, &a[i].y);
        for (int i=1; i<=q; ++i) { 
            scanf("%d%d", &b[i].x, &b[i].y);
            for (int j=1; j<=n; ++j) f[j] = reduce(a[j].y-b[i].y,a[j].x-b[i].x);
            sort(f+1,f+1+n);
            for (int j=1; j<=n; ++j) {
                pair<int,int> u = reduce(-f[j].second,f[j].first);
                ans[i] += upper_bound(f+1,f+1+n,u)-lower_bound(f+1,f+1+n,u);
            }
        }
        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=n; ++j) if (i!=j) f[j-(i<j)] = reduce(a[j].y-a[i].y,a[j].x-a[i].x);
            sort(f+1,f+n);
            for (int j=1; j<=q; ++j) {
                pair<int,int> u = reduce(-(b[j].x-a[i].x),b[j].y-a[i].y);
                ans[j] += upper_bound(f+1,f+n,u)-lower_bound(f+1,f+n,u);
                u.first = -u.first, u.second = -u.second;
                ans[j] += upper_bound(f+1,f+n,u)-lower_bound(f+1,f+n,u);
            }
        }
        for (int i=1; i<=q; ++i) printf("%d
    ", ans[i]);
    }
    View Code

    3. gym102428D

    题意:$n$个带权平面点,求判断是否存在一条直线,使得直线平移依次经过所有点时,点权是递增的

    把所有权值小的点向大的连一条向量,然后极角排序,如果存在两个相邻向量夹角不小于$pi$,那么有解,否则无解

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 4e3+10;
    const double pi = acos(-1);
    struct point {
        int x,y,z,tp;
        bool operator < (const point & b) const {
            if (tp!=b.tp) return tp<b.tp;
            return y*(int64_t)b.x<x*(int64_t)b.y;
        }
        bool operator == (const point & b) const {
            return !(*this<b)&&!(b<*this);
        }
    } a[N];
    int64_t cross(point a, point b) {
        return a.x*(int64_t)b.y-a.y*(int64_t)b.x;
    }
    int get(int x, int y) {
        if (x>0&&y>=0) return 1;
        if (x<=0&&y>0) return 2;
        if (x<0&&y<=0) return 3;
        return 4;
    }
    int main() {
        int n;
        scanf("%d", &n);
        int64_t sum = 0;
        for (int i=1; i<=n; ++i) scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].z);
        int cnt = 0;
        vector<point> f;
        for (int i=1; i<=n; ++i) {
            for (int j=1; j<=n; ++j) if (a[j].z>a[i].z) {
                point u{a[j].x-a[i].x,a[j].y-a[i].y,a[j].z};
                u.tp = get(u.x, u.y);
                f.push_back(u);
            }
        }
        sort(f.begin(),f.end());
        f.erase(unique(f.begin(),f.end()),f.end());
        if (f.size()<=2) return puts("Y"), 0;
        for (int i=0; i<f.size(); ++i) if (cross(f[i],f[(i+1)%f.size()])<=0) return puts("Y"), 0;
        puts("N");
    }
    View Code
  • 相关阅读:
    驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接
    spring 、Mybatis配置sql server数据库
    Win8安装程序出现2502、2503错误解决方法
    jsp-include 写法
    在swt中获取jar包中的文件 uri is not hierarchical
    Java调用shell脚本
    SWT自定义选项卡CTabFolder
    weblogic 生产模式和开发模式的互相转换
    or1200处理器的异常处理类指令介绍
    USACO Section 2.1 Healthy Holsteins
  • 原文地址:https://www.cnblogs.com/fs-es/p/14002000.html
Copyright © 2011-2022 走看看