Note: Whenever I refer to a valid triangle below I mean one that is equilateral.
Here are some approaches with different time complexities.
(~1 test case): Go through all triples of squares and check whether they form a valid triangle.
(~3 test cases): Fix the lower-left-most square of the triangle. For each remaining square , place into a bucket labeled . To check whether forms a valid triangle with two squares and in bucket just verify that
(~9 test cases). Consider the smallest rectangle with sides parallel to the coordinates axes that contains the triangle. At least one and at most two of the vertices of the triangle are also corners of this bounding rectangle.
Let the vertices of the triangle be First, consider a corner of the triangle which is also a corner of the rectangle. Without loss of generality, suppose that the corner is and Also suppose that ( even). Then both and lie on the diagonal consisting of all satisfying . Furthermore, For a fixed and , we can count the number of pairs in .
Regarding each of the three other possible orientations of the triangle (ex. ), just keep rotating the original square by 90 degrees and running the solution. Make sure not to overcount the case where two vertices of the triangle are corners of the bounding rectangle!
Let's try to make the above solution faster. Again focus on the case For a fixed note that the pairs which could possibly make a triangle with are almost exactly the same as those which could make a triangle with , so we can transition between the two in time.
#include "bits/stdc++.h" using namespace std; void setIO(string s) { ios_base::sync_with_stdio(0); cin.tie(0); freopen((s+".in").c_str(),"r",stdin); freopen((s+".out").c_str(),"w",stdout); } int N; bool G[300][300],GG[300][300]; long long ans; void rot() { // rotate 90 degrees for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) GG[N-1-j][i] = G[i][j]; for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) G[i][j] = GG[i][j]; } void solve() { // corner in diagonal with sum a, other two vertices in diagonal with sum b for (int a = 0; a < 2*N-1; ++a) for (int b = a+2; b < 2*N-1; b += 2) { int dif = (b-a)/2, st = max(0,a-(N-1)), en = min(a,N-1); int cur = 0; for (int i = st; i <= en; ++i) { if (i == st) // consider (i,a-i) -> stuff in row b for (int j = max(i,b-(N-1)); j < min(i+dif,N-dif); ++j) cur += G[j][b-j] && G[j+dif][b-j-dif]; if (G[i][a-i]) ans += cur; if (i+2*dif < N && b-(i+dif) < N) cur += G[i+dif][b-i-dif] && G[i+2*dif][b-i-2*dif]; if (i+dif < N && b-i < N) cur -= G[i][b-i] && G[i+dif][b-i-dif]; } } } int main() { setIO("triangles"); cin >> N; for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) { char c; cin >> c; G[i][j] = c == '*'; } for (int i = 0; i < 4; ++i) solve(), rot(); cout << ans << "\n"; }
As suggested by Dorijan Lendvaj, it is also possible to solve the problem in with bitset. Again, consider the case where Let and assume that , , and is divisible by two. This means that
#include "bits/stdc++.h" using namespace std; void setIO(string s) { ios_base::sync_with_stdio(0); cin.tie(0); freopen((s+".in").c_str(),"r",stdin); freopen((s+".out").c_str(),"w",stdout); } int N; bool G[300][300],GG[300][300]; long long res = 0; void rot() { for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) GG[N-1-j][i] = G[i][j]; for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) G[i][j] = GG[i][j]; } void solve() { bitset<300> mask[300]; for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) mask[i][j] = G[i][j]; for (int i = 0; i < N; ++i) for (int x = 1; x < N; ++x) for (int y = x; y < N; y += 2) { int x2 = x+(x+y)/2; if (i+x2 >= N) break; int y2 = (y-x)/2; res += (mask[i]&(mask[i+x]>>y)&(mask[i+x2]>>y2)).count(); } } int main() { setIO("triangles"); cin >> N; for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) { char c; cin >> c; G[i][j] = c == '*'; } for (int i = 0; i < 4; ++i) { solve(); rot(); } cout << res << "\n"; }