• BZOJ3543: [ONTAK2010]Garden


    http://www.lydsy.com/JudgeOnline/problem.php?id=3543

      首先明确两点,对于一个平行于坐标轴的正方形,只需要确定的一条边就可以,比如说下边或者右边。还有一个结论:n个点的二维点集的平行坐标轴的正方形个数是O(n√n)的。

      所以我们大概就明白了这题是需要暴力统计的。

      将横坐标相同的点放进同一个集合,点数>√n的称为大集合,否则是小集合。将读入的点丢进hash里。

      枚举每个集合:

        对于大集合,易知不超过√n个,每个就枚举其左侧的每个点,那么就确定了下边界,hash判定一下另外三个点的存在性即可。复杂度O(n√n)。

        对于小集合,暴力枚举集合内的点对来确定右边,hash判定。总复杂度不超过O(n√n)。

    #include<bits/stdc++.h>
    #include<tr1/unordered_set>
    using namespace std;
    const int maxn=100010,maxy=2000010;
    struct point{
        int x,y;
        point(): x(0),y(0) { }
        point(int x_,int y_): x(x_),y(y_) { }
        bool operator==(const point &b)const{
            return x==b.x && y==b.y;
        }
    }a[maxn];
    struct hasher{
        long long operator()(const point &t)const{
            const long long seed=23333;
            return t.x*seed+t.y;
        }
    };
    std::tr1::unordered_set<point,hasher> t;
    vector<int> heavy;
    int l[maxy],r[maxy]; bool flag[maxy];
    int n,S;
     
    inline bool cmp_y(const point &a,const point &b){
        return a.y<b.y || (a.y==b.y && a.x<b.x);
    }
    void init(){
        scanf("%d",&n),S=sqrt(n)*2;
        t.clear(),heavy.clear();
        for(int i=1;i<=n;++i){
            scanf("%d%d",&a[i].x,&a[i].y);
            a[i].y+=1e6,t.insert(a[i]);
        }
        sort(a+1,a+n+1,cmp_y);
    }
     
    void solve(){
        memset(l,-1,sizeof(l));
        memset(r,-1,sizeof(r));
        memset(flag,false,sizeof(flag));
        for(int u=1,v=1;u<=n;u=v){
            while(v<=n && a[v].y==a[u].y) ++v;
            l[a[u].y]=u,r[a[u].y]=v;
            if(v-u>S) heavy.push_back(a[u].y),flag[a[u].y]=true;
        }
        int ans=0;
        for(int i=1,x,y,d;i<=n;++i){
            x=a[i].x,y=a[i].y;
            if(flag[y]){
                for(int j=0;j<heavy.size();++j){
                    d=heavy[j]-y; if(d<=0) continue;
                    if(t.count(point(x,y+d)) && t.count(point(x+d,y)) && t.count(point(x+d,y+d)))
                        ++ans;
                }
            }
            else{
                for(int j=i+1;j<r[y];++j){
                    d=a[j].x-x; if(!d) continue;
                    if(t.count(point(x,y+d)) && t.count(point(x+d,y+d)))
                        ++ans;
                    if(y-d>=0 && flag[y-d] && t.count(point(x,y-d)) && t.count(point(x+d,y-d)))
                        ++ans;
                }
            }
        }
        printf("%d
    ",ans);
    }
     
    int main(){
        init();
        solve();
        return 0;
    }
    my code
  • 相关阅读:
    pymysql
    Mysql
    协程
    线程池
    线程 条件
    线程 事件
    线程
    requests
    Linux 时区不对的解决办法
    Linux 简单命令
  • 原文地址:https://www.cnblogs.com/iamCYY/p/4720111.html
Copyright © 2020-2023  润新知