Codeforces CF#628 Education 8 E. Zbazi in Zeydabad

E. Zbazi in Zeydabad
time limit per test
5 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

A tourist wants to visit country Zeydabad for Zbazi (a local game in Zeydabad).

The country Zeydabad is a rectangular table consisting of n rows and m columns. Each cell on the country is either 'z' or '.'.

The tourist knows this country is named Zeydabad because there are lots of ''Z-pattern"s in the country. A ''Z-pattern" is a square which anti-diagonal is completely filled with 'z' and its upper and lower rows are also completely filled with 'z'. All other cells of a square can be arbitrary.

Note that a ''Z-pattern" can consist of only one cell (see the examples).

So he wants to count the number of ''Z-pattern"s in the country (a necessary skill for Zbazi).

Now your task is to help tourist with counting number of ''Z-pattern"s.

As input/output can reach huge size it is recommended to use fast input/output methods: for example, prefer to usegets/scanf/printf instead of getline/cin/cout in C++, prefer to use BufferedReader/PrintWriter instead ofScanner/System.out in Java.

Input

The first line contains two integers n, m (1 ≤ n, m ≤ 3000) — the number of rows and columns respectively.

Each of the next n lines contains m characters 'z' or '.' — the description of Zeydabad.

Output

Print the only integer a — the number of ''Z-pattern"s in Zeydabad.

Examples
input
4 4
zzzz
zzz.
.z..
zzzz
output
16
input
1 4
z.z.
output
2
input
2 2
zz
zz
output
5

 

题意:
    给出一个n*n的矩阵,问有多少个子矩阵满足副对角线、最上面的行、最下面的行都是由z构成(其他位置无关)(理解一下,这样的图形构成了一个Z的图案)。

  

题解:
    如果预处理出每个点向左向右连续的z能够有多长,
    那么先枚举副对角线,
    由于答案肯定是由副对角线上连续的一段z贡献的,
    所以我们可以一段段z来做。
    问题转换成了,在这一段z上,有多少个点对(i,j)满足
    left[i]>=j - i, right[j] >= j - i,
    也就是说,i、j必须能够分别用left[i]、right[j]的长度分别覆盖对方。

    那么我们可以枚举j,确定有多少i对它进行了贡献。
    那么对于每个i,我们都能够知道它最远能够贡献到哪里,
    每当我们的j超过了这个i最远能贡献的距离,就将它排去,
    因为i不可能再对能够覆盖它的j左贡县。
    对于每个j,现在所有能够留下来的i都是能够覆盖它的。
    能够对它有贡献的i就是那些它能覆盖的i。

    所以保持i能覆盖当前的j这一步可以使用优先队列完成,
    统计有多少i贡献j能够用树状数组完成。

    挺水的。

  

 

 1 #include <cstdio>
 2 #include <queue>
 3 #include <cstring>
 4 #include <string>
 5 #include <iostream>
 6 #include <algorithm>
 7 #include <cstdlib>
 8 using namespace std;
 9 #define clr(x, y) memset(x, y, sizeof(x))
10 #define mk make_pair
11 
12 const int N = 3010;
13 typedef long long ll;
14 int n, m;
15 char graph[N][N];
16 int lef[N][N], rig[N][N];
17 
18 ll sum[N];
19 priority_queue<pair<int, int> > outQue;
20 
21 int lowbit(int x) {
22     return x & (-x);
23 }
24 
25 int len;
26 void add(ll *arr, int pos, ll val) {
27     if(!pos) return;
28     for(int x = pos; x <= len; x += lowbit(x)) arr[x] += val;
29 }
30 
31 ll query(ll *arr, int pos) {
32     ll ret = 0;
33     for(int x = pos; x; x -= lowbit(x)) ret += arr[x];
34     return ret;
35 }
36 
37 ll query(ll *arr, int lef, int rig) {
38     ll b = query(arr, rig);
39     ll a = query(arr, lef - 1);
40     return b - a;
41 }
42 
43 void solve() {
44     for(int i = 1; i <= n; ++i) {
45         lef[i][0] = 0;
46         for(int j = 1; j <= m; ++j)
47             if(graph[i][j] == '.') lef[i][j] = 0;
48             else lef[i][j] = lef[i][j - 1] + 1;
49         lef[i][m + 1] = 0;
50         for(int j = m; j >= 1; --j)
51             if(graph[i][j] == '.') rig[i][j] = 0;
52             else rig[i][j] = rig[i][j + 1] + 1;
53     }
54 
55     ll ans = 0;
56     for(int diagon = 1; diagon <= n + m - 1; ++diagon) {
57         int stx = max(1, diagon - m + 1), sty = min(diagon, m);
58         int tot = 0;
59         bool first = true;
60         for(int x = stx, y = sty; x <= n && y >= 1; ++x, --y)
61             if(graph[x][y] == '.') {
62                 for(int i = 1; i <= tot; ++i) sum[i] = 0;
63                 while(!outQue.empty()) outQue.pop();
64                 tot = 0, first = true;
65             } else {
66                 if(first) {
67                     len = 0, first = false;
68                     for(int _x = x, _y = y; _x <= n && _y >= 1 && graph[_x][_y] == 'z'; ++_x, --_y)
69                         ++len;
70                 }
71                 ++tot;
72                 add(sum, tot, 1);
73                 outQue.push(mk(-(tot + lef[x][y] - 1), tot));
74 
75                 while(-outQue.top().first < tot) {
76                     add(sum, outQue.top().second, -1);
77                     outQue.pop();
78                 }
79 
80                 ll tmp = query(sum, max(1, tot - rig[x][y] + 1), tot);
81                 ans += tmp;
82             }
83         for(int i = 1; i <= tot; ++i) sum[i] = 0;
84         while(!outQue.empty()) outQue.pop();
85     }
86 
87     cout << ans << endl;
88 }
89 
90 int main() {
91     scanf("%d%d", &n, &m);
92     for(int i = 1; i <= n; ++i) scanf("%s", graph[i] + 1);
93     solve();
94     return 0;
95 }
View Code

 

posted @ 2016-12-02 12:38  yanzx6  阅读(400)  评论(0编辑  收藏  举报