题解: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);
}

浙公网安备 33010602011771号