CF1080E 题解

CF1080E 题解

$\text{Description}$

给定一个由小写字母组成的矩形,我们称其的一个子矩形是美丽的,当且仅当其任意行任意排列字符后,任意行或任意列都为回文串。

求该矩形的子矩形中,有多少个是美丽的。

$1\le n,m\le 250,|\Sigma|=26$

$\text{Solution}$

考虑一个矩形是美丽的,当且仅当其任意行任意排列字符后,任意行或任意列都为回文串,这意味着其每一行都是回文串,等价于说该行至多只有一个字符的数量为奇数,并且在矩形中对称的两行相同(对于其每一个字符分析,由于它们在同一列上并且对称,故相等),等价于说该两行任意字母数量都相等。

如果我们把每一行写成一个 $26$ 维向量 $[a_1 a_2 \cdots a_{26}]$,$a_i$ 表示第 $i$ 个字母在该行中的出现次数,那么,我们在列上截取 $[l,r]$,则每一行 $[l,r]$ 这一子区间对应的 $26$ 维向量可以对应一个序列,我们所要做的就是求出这个序列的回文子串个数,套用 manacher 即可 $\mathcal O(n|\Sigma|)$ 求出(以某个元素为中心的回文子串个数是以该元素为中心的最长回文子串长度除以 $2$ 下取整)。

另外,需要预处理对于某一行的一个子区间,其上下最靠近它的一个不能通过重排变为回文串的子区间。

至于如何求出某一行某一子区间对应的 $26$ 维向量,考虑对 $\mathcal O(nm|\Sigma|)$ 地每一行求出其所有前缀对应的 $26$ 维向量,对于某一个子区间可以通过作差得到其对应的 $26$ 维向量。

时间复杂度 $\mathcal O(nm^2|\Sigma|)$,注意卡空间,可以不开的数组尽量不开,尤其是立方级别的

$\text{Code}$
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
78
79
80
81
82
83
84
85
86
87
88
89
90
#include<bits/stdc++.h>
#define REG register
using namespace std;
inline void read(int& x){
REG char c;
while(!isdigit(c=getchar()));x=c^48;
while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

const int S=26,N=505;

int n,m;

char str[N][N];

int Ans;

short PreV[N][N][S];

inline void Pre_Init(){
for(REG int i=1;i<=n;++i)
for(REG int j=1;j<=m;++j){
for(REG int c=0;c<S;++c) PreV[i][j][c]=PreV[i][j-1][c];
++PreV[i][j][str[i][j]-'a'];
}
}

inline void GetV(int i,int l,int r,short* V){for(REG int c=0;c<S;++c)V[c]=PreV[i][r][c]-PreV[i][l-1][c];}
inline bool cmp(short* V1,short* V2){
for(REG int c=0;c<S;++c)
if(V1[c]^V2[c]) return false;
return true;
}
inline bool cmp(short* V){
int cnt=0;
for(REG int c=0;c<S;++c) cnt+=(V[c]&1);
return cnt<=1;
}

short Vtmp1[N][S],MxR,MxC,MRad[N];

inline void Manacher(int l,int r){
for(REG int i=1;i<=n;++i) GetV(i,l,r,Vtmp1[i<<1]);
MxR=MxC=0;
for(REG int i=1;i<=2*n+1;++i){
int ML=i>MxR?1:min(MRad[2*MxC-i],(short)(MxR-i+1));
while((i-ML)&&(i+ML<=2*n+1))
if(cmp(Vtmp1[i-ML],Vtmp1[i+ML])) ++ML;
else break;
MRad[i]=ML;
if(i+ML-1>MxR) MxR=i+ML-1,MxC=i;
}
}

short UMD[N],DMD[N];

inline void UD(int l,int r){
for(REG int i=1;i<=n;++i) UMD[i]=0,DMD[i]=n+1;
int lst=0;
for(REG int i=1;i<=n;++i){
if(cmp(Vtmp1[i<<1])) UMD[i]=lst;
else
for(UMD[i]=DMD[i]=i,++lst;lst<i;++lst) DMD[lst]=i;
}
}

inline void Work(){
read(n),read(m);
for(REG int i=1;i<=n;++i) scanf("%s",str[i]+1);
Pre_Init();
for(REG int l=1;l<=m;++l)
for(REG int r=l;r<=m;++r){
Manacher(l,r),UD(l,r);
for(REG int i=2;i<=2*n;++i){
if(i&1){
int U=min((i-1)/2-UMD[(i-1)>>1],MRad[i]>>1);
int D=min(DMD[(i+1)>>1]-(i+1)/2,MRad[i]>>1);
Ans+=min(U,D);
}
else{
int U=min(i/2-UMD[i>>1],MRad[i]>>1);
int D=min(DMD[i>>1]-i/2,MRad[i]>>1);
Ans+=min(U,D);
}
}
}
printf("%d\n",Ans);
}

int main(){Work();}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×