LOJ3266 Equilateral Triangles

Equilateral Triangles

Farmer John 的牧场可以被视作一个 \(N\times N\) 的网格。对于网格中的每一个单元格,用 * 表示这个单元格里有一头牛,而 . 表示这个单元格里面没有牛。Farmer John 认为他牧场的美观度正比于这些牛形成的等边三角形数量,其中定义这种等边三角形为三头相互之间的距离相等的牛组成的无序\(^{[1]}\)三元组。

然而,Farmer John 最近才发现他的坐标全是整数,在这种情况下的欧几里得距离不可能存在这种美观的三元组,因此他选用了曼哈顿距离。形式化地说,\((x_0,~y_0),~(x_1,~y_1)\)两点间的曼哈顿距离为 \(|x_0-x_1|+|y_0-y_1|\)

给出这个网格,代表牛的位置,请求出无序三元组的数量。

\(^{[1]}\) 无序一词由译者根据样例解释补充。

\(N\leq 300\)

题解

https://jklover.hs-blog.cf/2020/06/14/Loj-3266-Equilateral-Triangles/

曼哈顿距离与切比雪夫距离的转化.

固定边长,那么曼哈顿距离意义下的圆是一个斜着的正方形,这显然是不好做的。

不妨考虑转成切比雪夫距离,将每个点的坐标 \((x,y)\) 变成 \((x+y,x-y)\),那么圆就变成了正方形。

此时原来的曼哈顿距离变成了切比雪夫距离 \(\max(|x_1-x_2|,|y_1-y_2|)\) ,三个点形成正三角形需要满足

\[\max(|x_1-x_2|,|y_1-y_2|)=\max(|x_1-x_3|,|y_1-y_3|)=\max(|x_2-x_3|,|y_2-y_3|) \]

通过一定的观察可以发现,这三个点中存在两个点的 \(x\) 相同,或存在两个点的 \(y\) 相同.

可以画个图直观理解一下。

先枚举两个 \(x\) 相同的点 \((a,b),(a,c)\) ,满足 \(b ,考虑计算有多少个点能和它们形成正三角形.

此时 \(3\)\(\max\) 的值都是 \(c-b\) ,可以得出另外一个点只可能是在 \(x\) 距离差上取得 \(\max\) .

即,统计满足 \(x=a\pm(c-b),b\le y\le c\)\((x,y)\) 的数目即可.

再枚举两个 \(y\) 相同的点 \((b,a),(c,a)\) ,满足 \(b ,同理计算贡献.

为了不与枚举 \(x\) 时贡献重复,统计 \(b\((x,y)\) 的数目即可.

时间复杂度 \(O(n^3)\) .

CO int N=610;
char str[N];
int val[N][N],row[N][N],col[N][N];

int main(){
	int n=read();
	for(int i=1;i<=n;++i){
		scanf("%s",str+1);
		for(int j=1;j<=n;++j) val[i+j][i+n-j]=str[j]=='*';
	}
	n*=2;
	for(int i=1;i<=n;++i)for(int j=1;j<=n;++j){
		row[i][j]=row[i][j-1]+val[i][j];
		col[i][j]=col[i-1][j]+val[i][j];
	}
	int ans=0;
	for(int a=1;a<=n;++a)
		for(int b=1;b<=n;++b)if(val[a][b])
			for(int c=b+1;c<=n;++c)if(val[a][c]){
				int d=a+(c-b);
				if(d<=n) ans+=row[d][c]-row[d][b-1];
				d=a-(c-b);
				if(d>=1) ans+=row[d][c]-row[d][b-1];
			}
	for(int a=1;a<=n;++a)
		for(int b=1;b<=n;++b)if(val[b][a])
			for(int c=b+1;c<=n;++c)if(val[c][a]){
				int d=a+(c-b);
				if(d<=n) ans+=col[c-1][d]-col[b][d];
				d=a-(c-b);
				if(d>=1) ans+=col[c-1][d]-col[b][d];
			}
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(LOJ3266 Equilateral Triangles)