CQXYM found a rectangle A of size n×m. There are n rows and m columns of blocks. Each block of the rectangle is an obsidian block or empty. CQXYM can change an obsidian block to an empty block or an empty block to an obsidian block in one operation.
A rectangle M size of a×b is called a portal if and only if it satisfies the following conditions:
- a≥5,b≥4.
- For all 1<x<a, blocks Mx,1 and Mx,b are obsidian blocks.
- For all 1<x<b, blocks M1,x and Ma,x are obsidian blocks.
- For all 1<x<a,1<y<b, block Mx,y is an empty block.
- M1,1,M1,b,Ma,1,Ma,b can be any type.
Note that the there must be a rows and b columns, not b rows and a columns.
Note that corners can be any type
CQXYM wants to know the minimum number of operations he needs to make at least one sub-rectangle a portal.
Input
The first line contains an integer t (t≥1), which is the number of test cases.
For each test case, the first line contains two integers n and m (5≤n≤400, 4≤m≤400).
Then n lines follow, each line contains m characters 0 or 1. If the j-th character of i-th line is 0, block Ai,j is an empty block. Otherwise, block Ai,j is an obsidian block.
It is guaranteed that the sum of n over all test cases does not exceed 400.
It is guaranteed that the sum of m over all test cases does not exceed 400.
Output
Output t answers, and each answer in a line.
题目分析
记sum[i][j]为以(i,j)为右下角的前缀和,sr[i][]为第i行的行前缀和,sc[][j]为第i列的列前缀和
那么某一个以(u,v)为左上角,(i,j)为右下角的矩形边框需要修改的次数为
2
(
i
+
j
−
u
−
v
)
−
4
−
(
(
s
r
[
i
,
j
]
−
s
r
[
i
,
v
−
1
]
)
+
(
s
r
[
u
,
j
]
−
s
r
[
u
,
v
−
1
]
)
+
(
s
c
[
i
,
j
]
−
s
c
[
u
−
1
,
j
]
)
+
(
s
c
[
i
,
v
]
−
s
c
[
u
−
1
,
v
]
)
−
2
∗
(
a
[
i
,
j
]
+
a
[
u
,
v
]
+
a
[
i
,
v
]
+
a
[
u
,
j
]
)
)
2(i+j-u-v)-4-((sr[i,j]-sr[i,v-1])+(sr[u,j]-sr[u,v-1])+(sc[i,j]-sc[u-1,j])+(sc[i,v]-sc[u-1,v])-2*(a[i,j]+a[u,v]+a[i,v]+a[u,j]))
2(i+j−u−v)−4−((sr[i,j]−sr[i,v−1])+(sr[u,j]−sr[u,v−1])+(sc[i,j]−sc[u−1,j])+(sc[i,v]−sc[u−1,v])−2∗(a[i,j]+a[u,v]+a[i,v]+a[u,j]))
中心需要修改的次数为
s
u
m
[
i
−
1
,
j
−
1
]
−
s
u
m
[
i
−
1
,
v
]
−
s
u
m
[
u
,
j
−
1
]
+
s
u
m
[
u
,
v
]
sum[i-1,j-1]-sum[i-1,v]-sum[u,j-1]+sum[u,v]
sum[i−1,j−1]−sum[i−1,v]−sum[u,j−1]+sum[u,v]
他们的和就是这个矩形要修改的次数
将上面式子的和拆成两部分
g
(
i
,
u
,
v
)
=
2
∗
(
i
−
u
−
v
)
−
4
+
s
r
(
i
,
v
−
1
)
+
s
r
(
u
,
v
−
1
)
−
s
c
(
i
,
v
)
+
s
c
(
u
−
1
,
v
)
+
2
∗
a
[
u
,
v
]
+
2
∗
a
[
i
,
v
]
+
s
u
m
[
u
,
v
]
−
s
u
m
[
i
−
1
,
v
]
g(i,u,v)=2*(i-u-v)-4+sr(i,v-1)+sr(u,v-1)-sc(i,v)+sc(u-1,v)+2*a[u,v]+2*a[i,v]+sum[u,v]-sum[i-1,v]
g(i,u,v)=2∗(i−u−v)−4+sr(i,v−1)+sr(u,v−1)−sc(i,v)+sc(u−1,v)+2∗a[u,v]+2∗a[i,v]+sum[u,v]−sum[i−1,v]
f ( i , u , j ) = 2 ∗ j − s r ( i , j ) − s r ( u , j ) − s c ( i , j ) + s c ( u − 1 , j ) + 2 ∗ a [ i , j ] + 2 ∗ a [ u , j ] + s u m [ i − 1 , j − 1 ] − s u m [ u , j − 1 ] f(i,u,j)=2*j-sr(i,j)-sr(u,j)-sc(i,j)+sc(u-1,j)+2*a[i,j]+2*a[u,j]+sum[i-1,j-1]-sum[u,j-1] f(i,u,j)=2∗j−sr(i,j)−sr(u,j)−sc(i,j)+sc(u−1,j)+2∗a[i,j]+2∗a[u,j]+sum[i−1,j−1]−sum[u,j−1]
我们分别枚举矩形的上下边界和左边界,问题变为已知(i,_)和(u,v),求一个j>=v+3使得f(i,u,j)最大
每次枚举了上下边界之后先求出所有f(i,u,j),再求出mi[j]表示在大于j+3的列里能取到的最大f(i,u,j)
复杂度为
O
(
n
2
m
)
O(n^2m)
O(n2m)
const int maxn=410;
int a[maxn][maxn];
char str[maxn];
int sum[maxn][maxn];
int f[maxn],mi[maxn];
int srow(int x,int y)
{
return sum[x][y]-sum[x-1][y];
}
int scol(int x,int y)
{
return sum[x][y]-sum[x][y-1];
}
int main()
{
int T=read();
while(T--)
{
int n=read(),m=read();
for(int i=1;i<=n;++i)
{
scanf("%s",str);
for(int j=0;j<m;++j)
a[i][j+1]=str[j]-'0';
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
int ans=1e9;
for(int u=1;u<=n;++u)
for(int i=u+4;i<=n;++i)
{
for(int j=m;j>=1;--j)
{
f[j]=2*j-srow(i,j)-srow(u,j)-scol(i,j)+scol(u-1,j)+2*a[i][j]+2*a[u][j];
f[j]+=sum[i-1][j-1]-sum[u][j-1];
if(j>m-3) mi[j]=1e9;
else mi[j]=min(mi[j+1], f[j+3]);
}
for(int v=m-3;v>=1;--v)
{
int g=2*(i-u-v)-4+srow(i,v-1)+srow(u,v-1)-scol(i,v)+scol(u-1,v)+2*a[u][v]+2*a[i][v]+sum[u][v]-sum[i-1][v];
ans=min(ans,g+mi[v]);
}
}
printf("%d\n",ans);
}
return 0;
}