P11521
不算难吧,为啥场上没多少人做(
先翻译一下题意:
定义对 01 矩阵的一个操作
(x_1,y_1,x_2,y_2,k) 为,向x\in[x_1,x_2],y\in[y_1,y_2] 的子矩阵内任意填 01,然后将原子矩阵的元素向左平移k 个单位,覆盖在矩阵上。给你两个 01 矩阵
A,B 。你要对于每一个k\in [1,m] ,求出有多少个子矩形,使得对A 进行操作(x_1,y_1,x_2,y_2,k) 后,矩阵等于B 。
分析一下这个操作,矩形会变成三个不同的部分:在平移后的子矩阵中的,在原子矩阵但是不在平移后的子矩阵中的,完全没有影响的。
- 第一部分,要求平移后对应位置相同。
- 第二部分,没有任何限制。
- 第三部分,要求原本
A 和B 这些位置就相同。
于是对于一个操作合法,也就是两个限制:
- 平移后子矩形对应位置相同。
- 影响到的位置包含了所有
A,B 不同的位置。
不难发现第二个限制就是对
考虑枚举
这是一个经典问题。考虑枚举
但是一个问题是这里有
还有一点细节:如果移动前后的矩形不交,在一些不太精细的实现中(比如我的),要特判两个矩阵中间几列有不同元素的情况。
时间复杂度
code:
int n,m,top,a[N][N],b[N][N],c[N][N],f[N],g[N],h[N],st[N];
int pd[N];
char s[N];
void Yorushika(){
read(n,m);
rep(i,1,n){
scanf("%s",s+1);
rep(j,1,m){
a[i][j]=s[j]-'0';
}
}
int x1=inf,x2=-inf,y1=inf,y2=-inf;
rep(i,1,n){
scanf("%s",s+1);
rep(j,1,m){
b[i][j]=s[j]-'0';
if(a[i][j]!=b[i][j]){
x1=min(x1,i),y1=min(y1,j);
x2=max(x2,i),y2=max(y2,j);
pd[j]=1;
}
}
}
rep(i,1,m){
pd[i]+=pd[i-1];
}
rep(k,1,m-1){
mems(c,0);
rep(i,1,n){
rep(j,k+1,m){
c[i][j]=a[i][j]==b[i][j-k];
}
}
mems(f,0),f[0]=f[n+1]=-inf;
int ans=-1;
drep(j,m,k+1){
rep(i,1,n){
if(c[i][j]){
f[i]++;
}else{
f[i]=0;
}
}
st[top=1]=0;
rep(i,1,n){
while(top&&f[st[top]]>=f[i]){
top--;
}
g[i]=st[top]+1;
st[++top]=i;
}
st[top=1]=n+1;
drep(i,n,1){
while(top&&f[st[top]]>=f[i]){
top--;
}
h[i]=st[top]-1;
st[++top]=i;
}
rep(i,1,n){
if(g[i]<=x1&&h[i]>=x2&&j-k<=y1&&j+f[i]>y2&&f[i]&&pd[j-1]-pd[j+f[i]-1-k]<=0){
ans=max(ans,(h[i]-g[i]+1)*f[i]);
}
}
}
printf("%d ",ans?ans:-1);
}
}
signed main(){
int t=1;
//read(t);
while(t--){
Yorushika();
}
}