本题有两个难度版本,分为easy和hard版本,区别是数据范围大小。其中本题是easy版。
阿宁认为一个大小为 xxx 的等腰三角形底边长度是 2×x+12\times x+12×x+1,高是 x+1x+1x+1。
等腰三角形不可以旋转,并且形态只能是下面举例的形态。
以下分别是 1,2,31,2,31,2,3 的等腰三角形:
.*. *** ..*.. .*.*. ***** ...*... ..*.*.. .*...*. *******
在一个字符矩阵中,三角形可以共用 '*'。因此上述举例中,大小为 222 和大小为 333 的三角形,都有两个大小为 111 的三角形。
现在给出一个 nnn 行 mmm 列的仅包含 '*' 和 '.' 的矩阵, 阿宁想要数一下有多少个满足要求的等腰三角形?
输入描述:
第一行输出两个整数 n,mn,mn,m,表示字符矩阵大小。 接下 nnn 行,每行 mmm 个字符,表示所给的矩阵。字符仅包含 '*' 和 '.'。 1≤n,m≤5001\leq n, m \leq 5001≤n,m≤500
输出描述:
输出一个整数,表示等腰三角形的数量。
示例1
输入
3 5 ..*.. .*.*. *****
输出
3
示例2
输入
3 5 ..*.. .***. *****
输出
5
思路:对于每一个没有不在最底层的'*",从它的下一层开始寻找它所在的三角形有几个,首先进行预处理,sum数组代表从j开始到末尾有几个‘*’。
#include "bits/stdc++.h"
using namespace std;//这是某大佬的代码
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<string> a(n);//用这种方法来表示二维数组,学到了(*^▽^*)
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector sum(n, vector<int>(m + 1));
for (int i = 0; i < n; i++) {//预处理
for (int j = 0; j < m; j++) {
sum[i][j + 1] = sum[i][j] + (a[i][j] == '*');
}
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (a[i][j] == '*') {//c表示三角形的顶点,l表示左端点,r表示右端点
int c = i + 1, l = j - 1, r = j + 1;
while (c < n && l >= 0 && r < m && a[c][l] == '*' && a[c][r] == '*') {
ans += (sum[c][r + 1] - sum[c][l] == r + 1 - l);如果当前左端点到右端点全部为‘*’,则答案加一
l--, r++, c++;
}
}
}
}
cout << ans << '\n';
return 0;
}