“Z”型矩阵

题意:

对于一个只包含 .z 的矩阵,当以下条件满足时:

  1. 该矩阵的行数列数相等。
  2. 该矩阵的第一行与最后一行的字符全是 z
  3. 该矩阵从右上角到左下角的对角线上的字符全是 z

我们称其为 Z 矩阵。

现在给定一个 n×mn×m 的矩阵,请你计算它有多少个子矩阵是 Z 矩阵。

输入格式

第一行两个整数 nn , mm 分别表示矩阵的行数和列数 (1≤n,m≤3×103)(1≤n,m≤3×103)。

接下来 nn 行, 每行包含 mm 个字符, 表示该矩阵。

输出格式

输出一行一个整数表示 Z 矩阵的数量。

样例输入

1
2
3
4
5
4 4
zzzz
z.z.
.zz.
zzzz

样例输出

1
14

思路:

好题,但不会!看题解学的,具体过程参考这位大佬的知乎。

https://zhuanlan.zhihu.com/p/486600382

简单说一下就是遍历对角线,在对角线上建树状数组,将每个连续的“z”看作一段,离线维护线段上每点的左右“z”各能到达的最远位置。然后遍历这个线段,维护每个点能到达后续点的的贡献,凡是能到达的后续点都可以利用到此点的贡献。(看不懂就看原dalao的知乎就完了)

然后贴出我的代码,虽然和大佬的代码基本一样,但是因为原代码的树状数组部分没给,我的写法与dalao还有一丝丝不同。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <bits/stdc++.h>
using namespace std;
const int N=3e3+10;
int g[N][N],L[N][N],R[N][N],t[N];
pair<int,int>line[2*N];
vector<int>del[2*N];
int cnt=0;
long long ans=0;
int lowbit(int x){
return x&(-x);
}
int query(int L,int R){
int s1=0,s2=0;
while(L>0){
s1+=t[L];
L-=lowbit(L);
}
while(R>0){
s2+=t[R];
R-=lowbit(R);
}
return s2-s1;
}
void add(int x,int w){
while(x<=cnt){
t[x]+=w;
x+=lowbit(x);
}
}
void solve(){
//cout<<endl;
for(int i=1;i<=cnt;i++){
int L=line[i].first,R=line[i].second;
ans+=query(max(1,i-R+1)-1,i);
if(L>1)add(i,1);
//cout<<ans<<' '<<i<<' '<<L<<' '<<R<<endl;
if(L>1)del[min(cnt,i+L-1)].push_back(i);
for(int x:del[i])add(x,-1);
}
memset(t,0,sizeof(t));
for(int i=1;i<=cnt;i++)del[i].clear();
cnt=0;
}
int main(){
int n,m;
cin>>n>>m;

for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;
cin>>c;
g[i][j]=c=='z';
ans+=c=='z';
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(g[i][j])L[i][j]=L[i][j-1]+1;
}
for(int j=m;j>=1;j--){
if(g[i][j])R[i][j]=R[i][j+1]+1;
}
}
for(int d=2;d<=n+m;d++){
for(int i=max(1,d-m);i<=min(n,d-1);i++){
int j=d-i;
if(!g[i][j]){
if(cnt)solve();
}else{
line[++cnt]={L[i][j],R[i][j]};
}
}
if(cnt)solve();
}
cout<<ans;
return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!