zoukankan      html  css  js  c++  java
  • 洛谷P3415 祭坛

    题目背景

    在遥远的Dgeak大陆,生活着一种叫做Dar-dzo-nye的怪物。每当这种怪物降临,人们必须整夜对抗怪物而不能安睡。为了乞求这种怪物不再降临,人们决定建造祭坛。

    题目描述

    Dgeak大陆可以看成一个用平面直角坐标系表示的巨大平面。在这个平面上,有 n 个Swaryea水晶柱,每个水晶柱可以用一个点表示。

    如果 4 个水晶柱依次相连可以构成一个四边形,满足其两条对角线分别平行于 x 轴和 y 轴,并且对角线的交点位于四边形内部(不包括边界),那么这 4 个水晶柱就可以建立一个结界。其中,对角线的交点称作这个结界的中心。

    例如下左图中,水晶柱 ABCD 可以建立一个结界,其中心为 O。

    为了起到抵御Dar-dzo-nye的最佳效果,人们会把祭坛修建在最多层结界的保护中。其中不同层的结界必须有共同的中心,这些结界的边界不能有任何公共点,并且中心处也不能有水晶柱。这里共同中心的结界数量叫做结界的层数。

    为了达成这个目的,人们要先利用现有的水晶柱建立若干个结界,然后在某些结界的中心建立祭坛。

    例如上右图中,黑色的点表示水晶柱(注意 P 和 O 点不是水晶柱)。祭坛的一个最佳位置为 O 点,可以建立在 3 层结界中,其结界的具体方案见下左图。当然,建立祭坛的最佳位置不一定是唯一,在上右图中,O 点左侧 1 单位的点 P 也可以建立一个在 3 层结界中的祭坛,见下右图。

    现在人们想知道:

    祭坛最佳选址地点所在的结界层数;

    祭坛最佳的选址地点共有多少个。
    输入输出格式

    输入格式:
    输入的第一行包含两个正整数 n,表示水晶柱的个数

    接下来 n 行,每行包含两个非负整数 x,y,表示每个水晶柱的坐标。保证相同的坐标不会重复出现。

    输出格式:
    第一行一个整数,表示祭坛最多可以位于多少个结界的中心

    第二行一个整数,表示结界数最多的方案有多少种。

    输入输出样例

    输入样例#1:
    26
    0 5
    1 1
    1 5
    1 9
    3 5
    3 10
    4 0
    4 1
    4 2
    4 4
    4 6
    4 9
    4 11
    5 0
    5 2
    5 4
    5 8
    5 9
    5 10
    5 11
    6 5
    7 5
    8 5
    9 10
    10 2
    10 5
    输出样例#1:
    3
    2
    说明

    对于30%的数据 n <= 1000

    另外30%的数据 n <= 10000

    剩下的40%数据 n <= 100000

    保证 0 <= x, y <= n


    二分答案。把所有y坐标相同的放进相同的vector中
    每次用扫描线检查答案是否合法并统计方案数.

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<queue>
    #include<bitset>
    using namespace std;
    const int maxn=100000+23333;
    typedef pair<int,int> par ;
    typedef long long ll;
    inline int read(){
        int an=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch<='9'&&ch>='0'){an=an*10+(ch^48);ch=getchar();}
        return an*f;
    }
    int n;
    struct saber{
    int x,y;
    }a[maxn];
    vector<int>ty[maxn];
    int up[maxn],used[maxn];
    par operator + (par x,par y){
        if(x.first==y.first)return make_pair(x.first,x.second+y.second);
        return x.first>y.first?x:y; 
    }
    struct Tree{
        int sum[maxn];
        inline void erase(){memset(sum,0,sizeof sum);}
        inline int query(int k){
            int re=0;
            for(;k;k-=-k&k)re+=sum[k];
            return re;
        }
        inline void add(int k,int val){for(;k<=1e5+1;k+=-k&k)sum[k]+=val;}
    }t;
    int L1,L2;
    bool vis[maxn]; 
    inline bool ok(int k){
        L1=k;L2=0;
        t.erase();
        for(int i=1;i<=1e5+1;i++)used[i]=0,vis[i]=0;
        for(int i=1;i<=1e5+1;i++){
            int len=ty[i].size();
            int l=k-1,r=len-k;
            for(int j=l;j<r;j++)L2+=t.query(ty[i][j+1]-1)-t.query(ty[i][j]);
            for(int j=0;j<len;j++){
                used[ty[i][j]]++;
                if(min(used[ty[i][j]],up[ty[i][j]]-used[ty[i][j]])>=k&&!vis[ty[i][j]])
                vis[ty[i][j]]=1,t.add(ty[i][j],1);
                if(min(used[ty[i][j]],up[ty[i][j]]-used[ty[i][j]])<k&&vis[ty[i][j]])
                vis[ty[i][j]]=0,t.add(ty[i][j],-1);
            }
        }
        return L2;
    }
    inline void solve(){
        int l=0,r=1e5;
        int ans1=0,ans2=0;
        while(l<=r){
            int mid=l+r>>1;
            if(ok(mid))ans1=L1,ans2=L2,l=mid+1;
            else r=mid-1;
        }
        cout<<ans1<<"
    "<<ans2;
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
            int xx=read()+1,yy=read()+1;
            a[i].x=xx;a[i].y=yy;up[xx]++;ty[yy].push_back(xx);
        }
        for(int i=1;i<=1e5+1;i++)sort(ty[i].begin(),ty[i].end());
        solve();
        return 0;
    }
    
  • 相关阅读:
    微信小程序开发入门(十六)
    npm安装教程
    js 比较两个日期大小
    js截取手机号后四位,并倒序输出
    TypeScript的安装和编译
    js中null和" "的区别
    阻止事件冒泡的3种方法
    阻止事件冒泡
    chrome查看js报错Uncaught SyntaxError: Unexpected string
    ES6思维导图
  • 原文地址:https://www.cnblogs.com/ck666/p/8442950.html
Copyright © 2011-2022 走看看