#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct pointInfo { 

     int x; 

     int y; 

     int havl; 

     char used; 

     char usedAsSquare; 

 }; 


 struct point { 

     int x; 

     int y; 

 }; 


 typedef struct pointInfo pointInfo; 

 typedef struct point point; 


 #define esp 1e-10 


 const int BIG_PRIME = 10007; 

 const int MAX_ADD = 20000; 


 point pointArray[1001]; 

 pointInfo pointHashArray[10027]; 


 int fillInHash(int x, int y) { 

     int x1 = x + MAX_ADD; 

     int y1 = y + MAX_ADD; 

     int havl = (x1*x1 + y1*y1) % BIG_PRIME; 

     int fillPos = havl; 

     while(1) { 

         if (!pointHashArray[fillPos].used) { 

             pointHashArray[fillPos].x = x; 

             pointHashArray[fillPos].y = y; 

             pointHashArray[fillPos].havl = havl; 

             pointHashArray[fillPos].usedAsSquare = 0; 

             pointHashArray[fillPos].used = 1; 

             return fillPos; 

         } else { 

             fillPos++; 

             if (fillPos >= 1009) { 

                 fillPos = 0; 

             } 

         } 

     } 

 }



int IfPointExist(int x, int y) {   // -1 no exist, else the pos in hashArray. 

     int x1 = x + MAX_ADD; 

     int y1 = y + MAX_ADD; 

     int havl = (x1*x1 + y1*y1) % BIG_PRIME; 

     int Pos = havl; 

     char byPassOneRound = 0; 

     while(1) { 

         if (byPassOneRound && Pos == havl) { 

             return -1; 

         } 

         if (!pointHashArray[Pos].used) { 

             return -1; 

         } else { 

             if (pointHashArray[Pos].havl == havl) { 

                 if (pointHashArray[Pos].x == x && 

                     pointHashArray[Pos].y == y ) { 

                     return Pos; 

                 } 

             } 

             Pos++; 

             if (Pos >= BIG_PRIME) { 

                 byPassOneRound = 1; 

                 Pos = 0; 

             } 

         } 

     } 

 } 


 void getSquareNum(int pointNum) { 

     int squareNum = 0; 

     for (int i = 0; i < pointNum-1; i++) { 

         for (int j = i+1; j < pointNum; j++) { 

             double x1 = pointArray[i].x; 

             double x2 = pointArray[j].x; 

             double y1 = pointArray[i].y; 

             double y2 = pointArray[j].y; 


             double x3 = (x1+x2+y2-y1)/2; 

             double y3 = (y1+y2+x1-x2)/2; 


             double x4 = (x1+x2-y2+y1)/2; 

             double y4 = (y1+y2-x1+x2)/2; 


             double len1=((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1))*2; 

             double len2=((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); 

             if ((int)x3 != x3 || 

                 (int)x4 != x4 || 

                 (int)y3 != y3 || 

                 (int)y4 != y4) { 

                 continue; 

             } 


             if(abs(len1-len2) > esp) 

                 continue; 

             int Pos3 = IfPointExist(x3, y3); 

             int Pos4 = IfPointExist(x4, y4); 

             if (Pos3 != -1 && Pos4 != -1) { 

                 // printf("%f %f %f %f\n", x1, y1, x2, y2); 

                 // printf("%f %f %f %f\n", x3, y3, x4, y4); 

                 squareNum++; 

             } 

         } 

     } 

     printf("%d\n", squareNum/2); 

     // printf("%d %d\n", squareNum, squareNum/2); 

 }
int main() { 

     int pointNum = 0; 

     while(scanf("%d", &pointNum)) { 

         if (pointNum == 0) { 

             return 0; 

         } 

         memset(pointArray, 0 , sizeof(pointArray)); 

         memset(pointHashArray, 0 , sizeof(pointHashArray)); 

         for (int i = 0; i < pointNum; i++) { 

             scanf("%d %d", &(pointArray[i].x), &(pointArray[i].y)); 

             fillInHash(pointArray[i].x, pointArray[i].y); 

         } 

         getSquareNum(pointNum); 

     } 
}


G++ 312K 1438MS(hash数组开了10007) 1407Ms(hash数组开了20011). 后来试了拉链法, 4460K 1219MS, 数组直接开到了99999, 貌似提升的也不是特别多.

这道题的关键是要知道一个正方形的定点坐标方程:

正方形ABCD
A(X1,Y1), C(X3,Y3), 对角线。

那么,另外两个顶点坐标:

x2:=(x1+x3+y3-y1)/2; y2:=(y1+y3+x1-x3)/2;
x4:=(x1+x3-y3+y1)/2; y4:=(y1+y3-x1+x3)/2;

没想到还有个这么方便的方程, 本来还准备自己推来着.....

基本思路是这样的:

首先一条对角线就可以决定一个特定的正方形,那么对

对点数组做个两重遍历:

遍历每一个对角线, 然后用上面的方程求出另外一条对角线的两个顶点,再看这两个顶点是否存在于点数组即可。

这里怎么查看定点存在,既可以实现排好点数组,二分查找,也可以hash搞起。

我这里用了hash,一开始空间开了最小,只到1000(点的最大数量), 结果果然付出了时间的代价,直接TLE, 后来直接开了10007的,终于勉强AC.

还犯了低级错误,把1000改10007的时候,忘了把fill和get里面也同步改,结果WA了好几次....

要试试拉链法了,在某些情况,查找效率应该高点,尤其是检测某些点是否在hash数组中,正好3432基本一样,可以在3432上试试.

还有要注意的一点,也是一个优化点:

一个正方形有两个对角线,如果对于某一个对角线AB,其对应的另外一个对角线的两个点C,D是存在于点数组的,那么在以后的遍历中,还会遇到

CD作为对角线来检测正方形,会得到AB, 这种情况下,如果每次匹配正方形数量都加1,那么最后的结果要除以2才是正方形的数量(一个正方形的两条对角线都被算了一次)。

这也是一种效率的浪费,因为在检测完AB以后,CD在下次遍历到的时候,就不应该再进行检测了(查看hash数组是不小的开销). 看到有解法似乎实现排序可以避免,要再看看.

还有个优化就是,因为题目明确了输入的都是整数,那么在通过上面的方程得到的坐标值是小数,就可以直接pass了。