Description
Suppose that you are in a campus and have to go for classes day by day. As you may see, when you hurry to a classroom, you surprisingly find that many seats there are already occupied. Today you and your friends went for class, and found out that some of the seats were occupied.
The classroom contains n rows of seats and there are m seats in each row. Then the classroom can be represented as an n × m matrix. The character ‘.’ represents an empty seat, while ‘*’ means that the seat is occupied. You need to find k consecutive empty seats in the same row or column and arrange those seats for you and your friends. Your task is to find the number of ways to arrange the seats. Two ways are considered different if sets of places that students occupy differs.
Input
The first line contains three positive integers n, m, k (1 ≤ n, m, k ≤ 2 000), where n, m represent the sizes of the classroom and k is the number of consecutive seats you need to find.
Each of the next n lines contains m characters ‘.’ or ‘‘. They form a matrix representing the classroom, ‘.’ denotes an empty seat, and ‘’ denotes an occupied seat.
Output
A single number, denoting the number of ways to find k empty seats in the same row or column.
Examples
Input |
---|
2 3 2 ∗∗. ∗ ∗ . ... . . . |
Output |
3 |
Input |
---|
1 2 2 .. . . |
Output |
1 |
Input |
---|
3 3 4 .∗. . ∗ . ∗.∗ ∗ . ∗ .∗. . ∗ . |
Output |
0 |
Note
In the first sample, there are three ways to arrange those seats. You can take the following seats for your arrangement.
- (1, 3), (2, 3)
- (2, 2), (2, 3)
- (2, 1), (2, 2)
题意:给n行m列座位,‘*’代表有人,‘.’代表空位。把一行或一列中k个连续的座位视为一种方案,求一共有多少种方案。
思路:关键信息是连续座位,如果知道每行/列上所有的最长连续空位的长度
li
l
i
,那么在每个最长连续空位上寻找长度为k的方案的个数不就是
li−k+1
l
i
−
k
+
1
吗。
为了记录最长连续空位的信息,我用的方法是开两个矩阵,一个记录行的信息,一个记录列的信息。以记录行的矩阵来说明:从( 0,0 )开始,如果位置( i,j )不是空位则记为0,如果是空位则记为位置( i,j )记录+1。因为是从左往右更新的,从第一个空位开始,往右连续的空位将记录2, 3, …
x
x
<script type="math/tex" id="MathJax-Element-381">x</script>。这样处理的以后,每个位置都记录从他开始向左的连续空位的长度,但是只有x和最终结果有关,所以我们可以在更新的过程中,每处理一个空位,就把它左边的空位的记录改成0,这样最后就只有最长的连续空位被记录了下来。
解释清了矩阵存储的信息以后,计算方案个数就简单了,只需要处理所有长度大于等于k的连续空位,如果长度是l,那么在它上面就有l-k+1种方案,求一下和就行了。
被hack了一次,是因为没考虑到k=1的特殊情况:行和列的方案是相同的,不能重复计数。OTZ大佬
#include<stdio.h>
const int maxn = 2005;
bool st[maxn][maxn];//[rows][cows]
int cntr[maxn][maxn];
int cntc[maxn][maxn];
int i, j, k, m, n;
char temp;
int main() {
scanf("%d %d %d", &n, &m, &k);
for (i = 1; i<=n; ++i) {
for (j = 1; j<=m; ++j) {
while (1) {
scanf("%c", &temp);
if (temp == '*' || temp == '.')break;
}
if (temp == '.') {//处理每一个空位
cntr[i][j] = cntr[i][j - 1] + 1;
cntr[i][j - 1] = 0;
//左边一个挨着的空位记录的信息没有用了,设为0方便计算答案
cntc[i][j] = cntc[i - 1][j] + 1;
cntc[i - 1][j] = 0;
//上边一个挨着的空位记录的信息没有用了,设为0方便计算答案
}
else if (temp == '*') {
//遇到有人的座位,连续空位的计数在这里中断
cntr[i][j] = 0;
cntc[i][j] = 0;
}
}
}
int ans = 0;
if(k==1){//对k=1的情况特殊处理
for (i = 1; i <= n; ++i)
for (j = 1; j <= m; ++j)
ans += cntc[i][j] - k + 1;
printf("%d",ans);
return 0;
}
for (i = 1; i <= n; ++i) {
for (j = 1; j <= m; ++j) {//计算所有连续空位即可
if (cntc[i][j] >= k)
ans += cntc[i][j] - k + 1;
if(cntr[i][j]>=k)
ans += cntr[i][j] - k + 1;
}
}
printf("%d", ans);
}