zoukankan      html  css  js  c++  java
  • 省选测试9

    省选测试 9

    T1

    ​ 咕咕咕咕咕.....

    T2

    ​ 给出一些山顶的坐标((x_i,y_i)), 每在一个山顶, 你将会找到当前能够看到的最高的山顶(一个山顶(P)能看到另一个山顶(Q)当且仅当它们的连线(P,Q)只与(P,Q)相交).

    ​ 爬到最高的山顶后你会停下来, 要计算对于每个山顶, 如果从这里开始爬, 会爬过几个山顶.(重复经过算多次). (y)坐标相同的情况下选(x)比较大的作为最高山顶.

    (n <= 5e5, 0 <= x_i, y_i<= 1e6)

    ​ 单调栈.

    ​ 首先我们需要知道在一个山顶可以看到最高的山顶是哪里, 直接单调栈就好了.

    ​ 设(to[i])(i)这个点为可以看到的最高的点. 我们在往(to[i])走的时候, 可能会经过(j)点, (to[j].y > to[i].y), 这时候我们需要改变要去的点, 变为(to[j]), 也就是说我们需要在(j)的答案上再加上一些(i)(j)经过的点才能得到(i)的答案.

    ​ 很容易发现这样的关系可以构成一颗树, 我们如果可以找到每个点应该从那些点的答案更新过来, 那么我们就可以建出一颗树, 在树上求出每个点到根的距离就是最终答案了.

    ​ 设(pre[i])(i)前面第一个(to[pre[i]].y > to[i].y)的位置, (nxt[i])(i)后面第一个(to[nxt[i]].y > to[i].y)的位置. 如果(to[i] > i), 那么我们要走到(nxt[i]), 如果(to[i] < i), 那么我们要走到(pre[i]).

    ​ 找出每个点的(pre, nxt)也用单调栈就可以了.

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 5e5 + 5;
    const double eps = 1e-9;
    int n, top;
    int to[N], pre[N], nxt[N], sta[N];
    struct point {
        double x, y;
        point() {}
        point(double X, double Y) { x = X; y = Y; }
    } a[N];
    
    point operator - (const point &a, const point &b) { return point(a.x - b.x, a.y - b.y); }
    
    double Cro(point a, point b) { return a.x * b.y - a.y * b.x; }
    
    int dcmp(double x) {
        if(fabs(x) < eps) return 0;
        return x > 0 ? 1 : -1; 
    }
    
    void get_to() {
        sta[++ top] = 1; sta[++ top] = 2;
        pre[1] = 1; pre[2] = 1;
        for(int i = 3;i <= n; i++) {
            while(top >= 2 && dcmp(Cro(a[sta[top]] - a[sta[top - 1]], a[i] - a[sta[top - 1]])) > 0) top --;
            sta[++ top] = i; pre[i] = sta[top - 1]; 
        }
        top = 0; sta[++ top] = n; sta[++ top] = n - 1;
        nxt[n] = n; nxt[n - 1] = n;
        for(int i = n - 2;i >= 1; i--) {
            while(top >= 2 && dcmp(Cro(a[sta[top]] - a[sta[top - 1]], a[i] - a[sta[top - 1]])) < 0) top --;
            sta[++ top] = i; nxt[i] = sta[top - 1];
        }
        for(int i = 1;i <= n; i++) {
            // cout << i << " " << pre[i] << " " << nxt[i] << "
    ";
            if(a[nxt[i]].y >= a[pre[i]].y) to[i] = nxt[i];
            else to[i] = pre[i];
            // printf("%d : %d
    ", i, to[i]);
        }
    }
    
    int rt, cnt;
    int head[N];
    long long ans[N];
    struct edge { int to, nxt, val; } e[N << 1];
    
    void add(int x, int y, int z) {
        // cout << x << " " << y << "!!!
    ";
        e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].val = z;
    }
    
    int cmp(int i, int j) {
        if(a[to[i]].y > a[to[j]].y) return 1;
        else if(a[to[i]].y == a[to[j]].y) return a[to[i]].x > a[to[j]].x;
        return 0;
    }
    
    void get_pre_nxt() {
        top = 0;
        for(int i = 1;i <= n; i++) {
            while(top && cmp(i, sta[top])) top --;
            // if(i == 9) cout << top << " " << sta[top] << " " << (a[to[sta[top]]].y < a[to[i]].y) << "++++++++++++
    ";
            if(top) pre[i] = sta[top];
            else pre[i] = to[i];
            sta[++ top] = i;
        } 
        top = 0;
        for(int i = n;i >= 1; i--) {
            while(top && cmp(i, sta[top])) top --; // ***
            // if(i == 1) cout << top << " " << sta[top] << "
    ";
            if(top) nxt[i] = sta[top];
            else nxt[i] = to[i];
            sta[++ top] = i;
        }
        int Max = 0;
        for(int i = 1;i <= n; i++) 
            if(a[i].y >= Max) Max = a[i].y, rt = i;
        for(int i = 1;i <= n; i++) {
            // cout << i << ":" << pre[i] << " " << nxt[i] << "
    ";
            if(i == rt) continue ;
            if(to[i] < i) add(max(to[i], pre[i]), i, i - max(to[i], pre[i])); // ***
            if(to[i] > i) add(min(to[i], nxt[i]), i, min(to[i], nxt[i]) - i); // ***
        }
    }
    
    void get_ans(int x) {
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to; 
            // cout << x << " " << y << "
    ";
            ans[y] = ans[x] + e[i].val; get_ans(y);
        }
    }
    
    int main() {
    
        freopen("mountain.in","r",stdin); freopen("mountain.out","w",stdout);
    
        n = read(); 
        for(int i = 1;i <= n; i++) a[i].x = read(), a[i].y = read();
        get_to(); get_pre_nxt(); get_ans(rt);
        for(int i = 1;i <= n; i++) printf("%lld
    ", ans[i]);
    
        fclose(stdin); fclose(stdout);
    
        return 0;
    }
    /*
    4
    0 10
    1 5
    2 0
    3 6
    
    10
    0 19
    1 6
    2 9
    3 1
    4 18
    5 16
    6 6
    7 7
    8 18
    9 19
    */
    

    T3

    ​ 小 K 养了 只鸽子,这 只鸽子可以看成平面直角坐标系内的 n 个固定的整点。

    ​ 同时,为了看住这些鸽子,小 K 可以在 m 个给定的点上选择其中的若干个点安装监视器。

    ​ 对于一只鸽子,它被监视当且仅当下面三个条件之一成立:

    • 这只鸽子的位置恰好和某个监视器重合。

    • 这只鸽子在其中两个位置不同的监视器连接形成的线段上。

    • 这只鸽子在三个不共线的监视器所构成的三角形.

    ​ 现在小 K 要让所有鸽子都被监视,请问他最少需要选择多少个给定的位置设置监视器。

    (2 <= n <= 1e5,3 <= m <= 500).

    ​ 凸包.

    ​ 对于两个监视器(A,B), 我们可以连一条从(A)(B)的边(注意有方向)当且仅当所有鸽子都在它的左边, 这个用叉积判断就可以了.

    ​ 所有监视器都连完边后, 我们用Floyd求最小环就可以得到答案了.

    ​ 怎么判断所有鸽子都在一条线的左边呢? 我们可以把鸽子的凸包求出来, 只需要判断离这条直线最近的点是否在直线的左边就好了.我们可以在凸包上二分斜率来得到这个点.

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
        long long s = 0, f = 1; char ch;
        while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
        for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
        return s * f;
    }
    
    const int N = 1e5 + 5, inf = 1e9;
    const double eps = 1e-9;
    int n, m, topx, tops;
    struct point { 
        double x, y; 
        point() {}
        point(double X, double Y) { x = X; y = Y; }
        friend int operator < (const point &a, const point &b) {
            return a.x == b.x ? a.y < b.y : a.x < b.x;
        }
    } a[N], b[N], stax[N], stas[N];
    
    point operator - (const point &a, const point &b) { return point(a.x - b.x, a.y - b.y); }
    
    double Cro(point a, point b) { return a.x * b.y - a.y * b.x; }
    
    int dcmp(double x) {
        if(fabs(x) < eps) return 0;
        return x > 0 ? 1 : -1;
    }
    
    void ConvexHall() {
        sort(a + 1, a + n + 1);
        stax[++ topx] = a[1]; stax[++ topx] = a[2];
        for(int i = 3;i <= n; i++) {
            while(topx >= 2 && dcmp(Cro(stax[topx] - stax[topx - 1], a[i] - stax[topx - 1])) <= 0) topx --;
            stax[++ topx] = a[i];
        }
        stas[++ tops] = a[n]; stas[++ tops] = a[n - 1];
        for(int i = n - 2;i >= 1; i--) {
            while(tops >= 2 && dcmp(Cro(stas[tops] - stas[tops - 1], a[i] - stas[tops - 1])) <= 0) tops --;
            stas[++ tops] = a[i];
        }
    }
    
    double xl(point a, point b) {
        return (a.y - b.y) / (a.x - b.x);
    }
    
    int judge(int i, int j) {
        double k = xl(b[i], b[j]);
        // cout << i << " " << j << " " << k << "
    ";
        int l = 2, r = tops - 1, mid;
        point ans1 = a[1], ans2 = a[n];
        while(l <= r) {
            mid = (l + r) >> 1;
            // cout << l << " " << r << "
    ";
            double z1 = xl(stas[mid - 1], stas[mid]), z2 = xl(stas[mid], stas[mid + 1]);
            int t1 = dcmp(k - z1), t2 = dcmp(k - z2);
            if((t1 == 0 && t2 == 0) || (t1 != t2)) { ans1 = stas[mid]; break; } 
            else if(t1 > 0 && t2 > 0) r = mid - 1;
            else l = mid + 1;
        }
        l = 2, r = topx - 1;
        while(l <= r) {
            mid = (l + r) >> 1;
            // cout << l << " " << r << "
    ";
            double z1 = xl(stax[mid - 1], stax[mid]), z2 = xl(stax[mid], stax[mid + 1]);
            int t1 = dcmp(k - z1), t2 = dcmp(k - z2);
            if((t1 == 0 && t2 == 0) || (t1 != t2)) { ans2 = stax[mid]; break; } 
            else if(t1 < 0 && t2 < 0) r = mid - 1;
            else l = mid + 1;
        }
        if(dcmp(Cro(ans1 - b[i], b[j] - b[i])) >= 0) {
            if(dcmp(Cro(a[1] - b[i], b[j] - b[i])) >= 0 && dcmp(Cro(a[n] - b[i], b[j] - b[i])) >= 0) return 1;
        }
        else if(dcmp(Cro(ans2 - b[i], b[j] - b[i])) <= 0) {
            if(dcmp(Cro(a[1] - b[i], b[j] - b[i])) <= 0 && dcmp(Cro(a[n] - b[i], b[j] - b[i])) <= 0) return 1;
        }
        else return 0;
    }
    
    long long ans;
    long long f[505][505], d[505][505];
    
    int main() {
    
        freopen("lo.in","r",stdin); freopen("lo.out","w",stdout);
    
        n = read(); m = read();
        for(int i = 1;i <= n; i++) a[i].x = read(), a[i].y = read(); 
        for(int i = 1;i <= m; i++) b[i].x = read(), b[i].y = read();
        ConvexHall();
        // for(int i = 1;i <= tops; i++) cout << stas[i].x << " " << stas[i].y << "!!!
    ";
        // for(int i = 1;i <= topx; i++) cout << stax[i].x << " " << stax[i].y << "|||
    "; 
    
        ans = inf;
        for(int i = 1;i <= m; i++)
            for(int j = 1;j <= m; j++) f[i][j] = d[i][j] = inf;
        sort(b + 1, b + m + 1);
        for(int i = 1;i <= m; i++)
            for(int j = i + 1;j <= m; j++) 
                if(judge(i, j)) f[i][j] = f[j][i] = d[i][j] = d[j][i] = 1;
        
        for(int k = 1;k <= m; k++) {
            for(int i = 1;i <= m; i++) {
                for(int j = 1;j <= m; j++) {
                    ans = min(ans, d[i][k] + d[k][j] + f[i][j]);
                }
            }
            for(int i = 1;i <= m; i++) {
                for(int j = 1;j <= m; j++) {
                    ans = min(ans, f[i][k] + f[k][j] + f[i][j]);
                    // cout << f[i][k] << " " << f[k][j] << " " << f[i][j] << "
    ";
                    if(f[i][k] + f[k][j] < f[i][j]) f[i][j] = f[i][k] + f[k][j];
                }
            }
        }
        printf("%lld", ans > m ? -1 : ans);
    
    
        fclose(stdin); fclose(stdout);
    
        return 0;
    }
    
    /*
    4 4
    0 0
    1 0
    0 1
    -1 0
    0 1
    1 0
    0 -1
    -1 0
    
    2 4
    -1 0
    1 0
    -2 -1
    -2 1
    2 -1
    2 1
    */
    
  • 相关阅读:
    mybatis中的#和$的区别
    spring ioc三种注入方式
    JSP中动态INCLUDE与静态INCLUDE的区别
    j2ee部分
    面试 框架部分
    注册Jdbc驱动程序的三种方式
    union和union all有什么不同?
    面试 JavaWeb 部分
    Cordova插件开发(iOS/Android)--看这篇就够了
    程序员,请不要只看技术
  • 原文地址:https://www.cnblogs.com/czhui666/p/14515454.html
Copyright © 2011-2022 走看看