• bzoj2928: [Poi1999]飞弹


    惨啊…… 被卡常是一种什么感受&……

    很明显的分治。

    我们首先可以找到所有点中的最低点,然后对所有点进行一次极角排序,选取一个点使得他各侧飞弹和地堡一样多,并对两侧继续进行分治。

    很容易证明这样做的正确性。

    然而这样做是(n^{2}log(n))。所以我们需要加些玄学的优化……比如通过增加每次分治的宽度,以减少排序的次数……

    ……总之就是水过啦QAQ

    #include <bits/stdc++.h>
    #define N 20010
     
    const int H = 600000;
    char s0[H] , * s1 = s0 , * s2 = s1;
    #define I ( s1 == s2 &&( s2 = ( s1 = s0 ) + fread( s0 , 1 , H , stdin ) , s1 == s2 ) ? 32 : * s1++ )
    inline int read()
    {
        register int x = 0 , c, f = 0;
        while( isspace( c = I ) );
        if (c == '-') f = 1; else x = x * 10 + c - 48;
        while(isdigit( c = I ) ) x = x * 10 + c - 48;
        return (f? -x: x);
    }
     
    using namespace std;
    int n;
    struct node
    {
        int x, y, t, i;
    } L[N];
    node O;
    int ansi[N];
    int ci[N];
     
    int compc(int a, int b)
    {
        return ((L[a].x - O.x) * (L[b].y - O.y) - (L[b].x - O.x) * (L[a].y - O.y)) < 0;
    }
    int comp(node a, node b)
    {
        return ((a.x - O.x) * (b.y - O.y) - (b.x - O.x) * (a.y - O.y)) < 0;
    }
    void solve(int l, int r)
    {
        if (l > r) return;
        for (int i = l + 1; i <= r; ++ i)
            if (L[ci[i]].y < L[ci[l]].y) swap(ci[i], ci[l]);
        O = L[ci[l]];
        sort(ci + l + 1, ci + r + 1, compc);
        int np = l + 1;
        for (int i = l + 1, k = 0; i < r; ++ i)
        {
            k += L[ci[i]].t;
            if (k == 0)
            {
                solve(np, i);
                np = i + 1;
            }
        }
        if (L[ci[l]].t > 0) ansi[L[ci[l]].i] = L[ci[np]].i;
        else ansi[L[ci[np]].i] = L[ci[l]].i;
        solve(np + 1, r);
    }
    int compi(node a, node b)
    {
        if (a.t != b.t) return a.t > b.t;
        else return a.i < b.i;
    }
    int checker()
    {
        sort(L + 1, L + n * 2 + 1, compi);
        for (int i = 1; i <= n; ++ i)
            for (int j = 1; j <= n; ++ j)
                if (i != j)
                {
                    O = L[i];
                    int a = comp(L[ansi[i] + n], L[j]) ^ comp(L[ansi[i] + n], L[ansi[j] + n]);
                    O = L[j];
                    int b = comp(L[ansi[j] + n], L[i]) ^ comp(L[ansi[j] + n], L[ansi[i] + n]);
                    if (a && b)
                        return 1;
                }
        return 0;
    }
    int main()
    {
        //freopen("rak0.in", "r", stdin);
        n = read();
        for (int i = 1; i <= 2 * n; ++ i) ci[i] = i;
        for (int i = 1; i <= n; ++ i)
        {
            L[i].x = read(); L[i].y = read();
            L[i].t = 1; L[i].i = i;
        }
        for (int i = 1; i <= n; ++ i)
        {
            L[i + n].x = read(); L[i + n].y = read();
            L[i + n].t = -1; L[i + n].i = i;
        }
        solve(1, n * 2);
        for (int i = 1; i <= n; ++ i) printf("%d
    ", ansi[i]);
        //printf("%d", checker());
    }
  • 相关阅读:
    第一次作业 —— 【作业7】问卷调查
    讲座观后感
    学习进度表(随缘更新)
    数据结构与算法思维导图
    作业七问卷调查
    《创新者的逆袭,用第一性原理做颠覆式创新》读后感
    结对项目--四则运算生成器(Java) 刘彦享+龙俊健
    个人项目---WordCount实现(Java)
    自我介绍+软工五问
    简洁又快速地处理集合——Java8 Stream(下)
  • 原文地址:https://www.cnblogs.com/AwD-/p/5822197.html
Copyright © 2020-2023  润新知