题解:P6143 [USACO20FEB] Equilateral Triangles P

题目传送门

这是一道比较有意思的偏数学题。首先容易想到结论:
对于倾角为 \(45°\) 的线段上的点 \(J\) 和点 \(K\),作等腰三角形 \(JKH\) 然后将其翻转 \(90°\),得到其全等三角形 \(OHL\),先抛出结论:线段 \(OL\) 上的每一个奶牛都可以与点 \(J\) 和点 \(K\) 形成一个曼哈段等边三角形。

接下来证明:因为 \(JK\) 的曼哈顿距离等于 \(JH+HK\),又因为 \(OJ\) 的距离等于 \(OH+HJ\)\(OK\) 的距离等于 \(OH+HK\),又因为 \(OH=HK=HJ\),所以三角形 \(OJK\) 为曼哈顿等边三角形。因为线段 \(OL\) 是一条倾角为 \(45°\) 的线段,所以在这条线段上的每一个点的坐标是由 \(O\)\(X\) 坐标 \(+len\)\(Y\) 坐标 \(-len\) 变换而来的,所以这条线段上的任意点到 \(J\)\(K\) 的距离不变。证毕。

所以我们可以枚举 \(O\) 点和 \(OH\) 的长度 \(len\),那么假设 \(O\) 的坐标为 \((x,y)\),则 \(L\) 坐标为 \((x+len,y-len)\),那么 \(J\)\(K\) 的坐标分别为 \(J(x+len,y+len),K(x+2\times len,y)\)。所以我们只需要预先处理出每一条斜 \(45°\) 的直线的前缀和,即可快速求出贡献。

下面是代码

#include<bits/stdc++.h>
using namespace std;
const int N=701;
int n,a[N][N],f[N][N],b[N][N],ans,tot;
struct tt{
	int x,y;
}e[N*N];
void turn(){
	memcpy(b,a,sizeof(b));
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[j][i]=b[n-i+1][j];
}
void solve(){
	tot=0;
	memset(f,0,sizeof(f));
	for(int i=1;i<=2*n;i++)for(int j=1;j<=2*n;j++)f[i][j]=f[i-1][j+1]+a[i][j];
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(a[i][j]==1)e[++tot].x=i,e[tot].y=j;
	for(int i=1;i<=tot;i++){
		for(int j=1;j<=n;j++){
			int xa=e[i].x,ya=e[i].y;
			int xb=e[i].x+j,yb=e[i].y-j;
			if(xb>n||yb<1)break;
			if(a[xb][yb]==0)continue;
			ans+=f[xa+2*j][ya]-f[xa+j][ya+j];
		}
	}
}
int main(){
	scanf("%d",&n);
	getchar();
	for(int i=1;i<=n;i++){
		string s;
		getline(cin,s);
		for(int j=0;j<s.size();j++)if(s[j]=='*')a[i][j+1]=1;
	}
	for(int i=1;i<=4;i++){
		solve();
		turn();
	}
	printf("%d",ans);
}
posted @ 2025-04-14 16:10  一班的hoko  阅读(59)  评论(0)    收藏  举报