把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

qzezoj 1544 查找正方形

题面传送门
这道题到现在为止还只有我一个人做出来,还是蛮高兴的\(QWQ\)
算了不说了,再说\(90\)分的\(zj\)会把我用唾沫星子淹死我的
想法\(1\):暴力枚举:枚举四个点,求这四个点之间的欧几里得距离,看是否相等,相等即构成一个正方形。大概\(30\)分。
想法\(2\):构造:枚举三个点,构造出第四个点,看是否存在,用\(map\)约50分,用\(hash\)\(60\)分。
想法3:高级构造:枚举两个点,构造出三四个点,用\(hash\)判断是否存在。
那么问题来了,怎么构造第三第四个点?我们枚举的是对角线。这样可以减少重复枚举。
如果有两个点,\(midx\)\(midy\)为两点连成的线的中点,即为正方形中点。
正方形中点到任意一个顶点长度一样,那么过\(midx\)\(midy\)\(y\)轴的垂线,将这个三角形旋转,得到左边的点的公式:\(midx-midy+y1\)\(midy+midx-x1\)
同理,得到右边的点的公式:\(midx+midy-y1,midy-midx+x1\)
分类讨论\(x1<x2\)\(x1>x2\)\(x1=x2\)\(y1<y2\)\(y1>y2\)\(y1=y2\),组合一下,得到了\(9\)种情况。
我们发现\(x1=x2\)\(y1=y2\)可以合并到各类项中,于是我们得到另外一种讨论:\(x1\leq x2\)\(x1\geq x2\)\(y1\leq y2\)\(y1\geq y2\),只有四种情况
于是我们很愉快的得到了四种情况的解(以下\(mid\)\(m\)代替):
\(x_i\leq xj\)\(yi\leq yj\):
\(((mx-my+y_i),(my+mx-x_i)),((mx+my-y_i),(my-mx+x_i))\)
\(x_i\geq x_j\),\(y_i\geq y_j\):
\(((mx-my+y_j),(my+mx-x_j)),((mx+my-y_j),(my-mx+x_j))\)
\(x_i\leq x_j\),\(y_i\geq y_j\):
\(((mx-my+y_j),(my-mx+x_i)),((mx+my-y_j),(my+mx-x_i))\)
\(x_i\geq x_j\),\(y_i\leq y_j\):
\(((mx-my+y_i),(my-mx+x_j)),((mx+my-y_i,(my+mx-x_j))\)
\(mx-my\)必须是整数,所以我们要特判一下。
代码实现:

#include<cstdio>
#include<cstring>
using namespace std;
int head,n,m,x[1039],y[1039],t,flag,h[100039];
double mx,my,nowx,nowy;
struct yyy {
    int xs,ys,z;
} f[100039];
inline int find(int x,int y) {
    register int ans=((long long )x*x+(long long)y*y)%100007,tmp=h[ans];
    while(tmp>=0){
        if(f[tmp].xs==x&&f[tmp].ys==y)break;
        tmp=f[tmp].z;
    } 
    if(tmp==-1) return 0;
    else return 1;
}
inline void get(int x,int y) {
    register int ans=((long long )x*x+(long long)y*y)%100007;
    head++;
    f[head]=(yyy) {x,y,h[ans]};
    h[ans]=head;
}
int main() {
    register int i,j;
    scanf("%d",&t);
    while(t--) {
        head=flag=0;
        memset(h,-1,sizeof(h));
        scanf("%d",&n);
        for(i=1; i<=n; i++) {
            scanf("%d%d",&x[i],&y[i]);
            if(!find(x[i],y[i])) get(x[i],y[i]);
        }
        for(i=1;i<=n;i++){
            for(j=i+1;j<=n;j++){
                    mx=(x[i]+x[j])/2.0;
                    my=(y[i]+y[j])/2.0;
                    if(x[i]>=x[j]&&y[i]>=y[j]){
                        if((int)(mx-my)==mx-my){
                             
                            if(find((int)(mx-my+y[j]),(int)(my+mx-x[j]))&&find((int)(mx+my-y[j]),(int)(my-mx+x[j]))){
                                flag=1;break;
                                 
                            }
                        }
                    }
                    if(x[j]>=x[i]&&y[j]>=y[i]){
                        if((int)(mx-my)==mx-my){
                            if(find((int)(mx-my+y[i]),(int)(my+mx-x[i]))&&find((int)(mx+my-y[i]),(int)(my-mx+x[i]))){
                                flag=1;break;
                                 
                            }
                        }
                    }
                    if(x[j]<=x[i]&&y[j]>=y[i]){
                        if((int)(mx-my)==mx-my){
                            if(find((int)(mx-my+y[i]),(int)(my-mx+x[j]))&&find((int)(mx+my-y[i]),(int)(my+mx-x[j]))){
                                flag=1;break;
                                 
                            }
                        }
                    }
                    if(x[j]>=x[i]&&y[j]=<y[i]){
                        if((int)(mx-my)==mx-my){
                            if(find((int)(mx-my+y[j]),(int)(my-mx+x[i]))&&find((int)(mx+my-y[j]),(int)(my+mx-x[i]))){
                                flag=1;break;
                                 
                            }
                        }
                    }
            }
            if(flag) break;
        }
        printf("%d\n",flag);
    }
}
posted @ 2020-03-27 16:04  275307894a  阅读(68)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end