1. 程式人生 > 其它 >【題解】[USACO20FEB]Equilateral Triangles P

【題解】[USACO20FEB]Equilateral Triangles P

基礎數數題。

曼哈頓距離不方便數點,比較套路的轉化為切比雪夫距離。

那麼現在要數三元組 \((i,j,k)\) 個數使得兩兩距離相等。

首選一下發現只用兩種情況,第一種是三個點構成等腰直角三角形,第二種是三個點構成銳角三角形使得存在一條平行於座標軸的邊,且該邊上的高和它的長度相等。

充分性也不難證明,首先如果三條邊都不與座標軸平行,那麼反證一下發現不存在這種情況。

否則一定存在一條邊與座標軸平行,畫出來如果這條邊上的高與它不相等,那麼也不滿足條件。

最後鈍角三角形顯然不滿足條件。所以只剩下上面兩種情況。

具體實現,我們記錄行字首和,和列字首和,然後列舉與座標軸平行的邊。求字首和的時間複雜度是 \(\mathcal{O}(N^2)\)

,列舉邊的時間複雜度是 \(\mathcal{O}(N^3)\) ,查詢是 \(\mathcal{O}(1)\) 的,所以總時間複雜度為 \(\mathcal{O}(N^3)\)

注意實現細節,比如轉化為切比雪夫距離後坐標可能為負數需要處理一下,座標值域會擴大為原來的兩倍。如果直接列舉新的值域會有 \(8\) 倍常數直接爆炸。但是轉化之後的網格會變稀疏,輕微剪枝就拿到了最優解(doge

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 1005
using namespace std;
int n,a[N][N],u[N][N],v[N][N];char s[N][N];
int main(){
	scanf("%d",&n);
	rep(i,1,n)scanf("%s",s[i]+1);
	rep(i,1,n)rep(j,1,n)if(s[i][j]=='*')a[i+j][i-j+n]=1;
	int m=2*n;
	rep(i,1,m)rep(j,1,m)u[i][j]=u[i][j-1]+a[i][j];
	rep(j,1,m)rep(i,1,m)v[i][j]=v[i-1][j]+a[i][j];
	int ans=0;
	rep(k,1,m)rep(i,1,m)if(a[i][k])rep(j,i+1,m)if(a[j][k]){
		if(k>j-i)ans+=v[j][k-j+i]-v[i-1][k-j+i];
		if(m-k>=j-i)ans+=v[j][k+j-i]-v[i-1][k+j-i];
	}
	rep(k,1,m)rep(i,1,m)if(a[k][i])rep(j,i+2,m)if(a[k][j]){
		if(k>j-i)ans+=u[k-j+i][j-1]-u[k-j+i][i];
		if(m-k>=j-i)ans+=u[k+j-i][j-1]-u[k+j-i][i];
	}
	printf("%d\n",ans);
	return 0;
}