Codeforces CF#628 Education 8 E. Zbazi in Zeydabad
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.
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.
Print the only integer a — the number of ''Z-pattern"s in Zeydabad.
4 4
zzzz
zzz.
.z..
zzzz
16
1 4
z.z.
2
2 2
zz
zz
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 }