G. Mischievous Shooter

G. Mischievous Shooter

Once the mischievous and wayward shooter named Shel found himself on a rectangular field of size n×m, divided into unit squares. Each cell either contains a target or not.

Shel only had a lucky shotgun with him, with which he can shoot in one of the four directions: right-down, left-down, left-up, or right-up. When fired, the shotgun hits all targets in the chosen direction, the Manhattan distance to which does not exceed a fixed constant k. The Manhattan distance between two points (x1,y1) and (x2,y2) is equal to |x1x2|+|y1y2|.


Possible hit areas for k=3.

Shel's goal is to hit as many targets as possible. Please help him find this value.

Input

Each test consists of several test cases. The first line contains a single integer t (1t1000) — the number of test cases. Then follows the description of the test cases.

The first line of each test case contains field dimensions n, m, and the constant for the shotgun's power k (1n,m,k105,1nm105).

Each of the next n lines contains m characters — the description of the next field row, where the character '.' means the cell is empty, and the character '#' indicates the presence of a target.

It is guaranteed that the sum of nm over all test cases does not exceed 105.

Output

For each test case, output a single integer on a separate line, which is equal to the maximum possible number of hit targets with one shot.

Example

input

4
3 3 1
.#.
###
.#.
2 5 3
###..
...##
4 4 2
..##
###.
#..#
####
2 1 3
#
#

output

3
4
5
2

Note

Possible optimal shots for the examples in the statement:

 

解题思路

  看完题就很快想到做法了,很明显就是枚举每个格子然后用前缀和求四个方向的三角形中 # 的数量,但想到会有很多边界情况代码很难写就不做了。

  为了少写些代码,我们可以固定一个三角形的方向,通过将矩阵顺时针旋转 90 来实现其他方向的枚举过程,这样就可以用同一套代码逻辑来处理四个方向的问题。为了方便这里选择左下角的方向。

  三角形内的 # 用前缀和来维护,当从 (i,j) 变到 (i,j+1) 时,变化的部分入下图。绿色的部分是新增的,红色的部分是删掉的。

  所以我们只需维护两个前缀和,一个是列方向的用 s1[i][j] 表示第 j 列的 1i 行内 # 的数量,转移方程是 s1[i][j]=s1[i1][j]+[gi,j=#]。另外一个是对角线方向的用 s2[i][j] 表示从 (i,j) 沿截距为 ji 的直线左上方的 # 的数量,转移方程是 s2[i][j]=s2[i1][j1]+[gi,j=#]

  用 s 表示 (i,j) 左下方三角形内 # 的数量,当枚举到下一个格子 (i,j+1) 时,令 jj+1,那么 s 就变成 s+(s1[i+k][j]s1[i1][j])(s2[i+k][j1]s2[i1][jk2])。考虑边界情况,当 i+k>n,在 s1 中只需变成 n 即可。在 s2 中,令 x=i+ky=jk2,则需要将 x 减去 i+kn 变成 n,对应的 y 也要减去 i+kn。如果变化后的 y 小于 0 则变成 0 即可。因此实际上 s 应该变成 s+(s1[min{n,i+k}][j]s1[i1][j])(s2[min{n,i+k}][max{0,j1max{0,i+kn}}]s2[i1][max{0,jk2}])

  最后就是如何矩阵顺时针旋转 90。举个例子模拟一下,可以发现原本的 gi,j 就会变成 fj,ni1

  AC 代码代码如下,时间复杂度为 O(nm)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    vector<string> g(n);
    for (int i = 0; i < n; i++) {
        cin >> g[i];
    }
    int ret = 0;
    for (int i = 0; i < 4; i++) {
        vector<vector<int>> s1(n + 1, vector<int>(m + 1)), s2(n + 1, vector<int>(m + 1));
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (g[i - 1][j - 1] == '#') s1[i][j] = s2[i][j] = 1;
                s1[i][j] += s1[i - 1][j];
                s2[i][j] += s2[i - 1][j - 1];
            }
        }
        for (int i = 1; i <= n; i++) {
            int s = 0;
            for (int j = 1; j <= m; j++) {
                s += s1[min(n, i + k)][j] - s1[i - 1][j];
                s -= s2[min(n, i + k)][max(0, j - 1 - max(0, i + k - n))] - s2[i - 1][max(0, j - k - 2)];
                ret = max(ret, s);
            }
        }
        vector<string> f(m, string(n, 0));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                f[j][n - i - 1] = g[i][j];
            }
        }
        g = f;
        swap(n, m);
    }
    cout << ret << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 920 (Div. 3) A-G 讲解:https://www.bilibili.com/video/BV19C4y1k7MA/

  Editorial for Codeforces Round 920 (Div. 3):https://codeforces.com/blog/entry/124757

posted @   onlyblues  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示