Codeforces Round #745 (Div. 1) A.Portal【DP】

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+juv)4((sr[i,j]sr[i,v1])+(sr[u,j]sr[u,v1])+(sc[i,j]sc[u1,j])+(sc[i,v]sc[u1,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[i1,j1]sum[i1,v]sum[u,j1]+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(iuv)4+sr(i,v1)+sr(u,v1)sc(i,v)+sc(u1,v)+2a[u,v]+2a[i,v]+sum[u,v]sum[i1,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)=2jsr(i,j)sr(u,j)sc(i,j)+sc(u1,j)+2a[i,j]+2a[u,j]+sum[i1,j1]sum[u,j1]

我们分别枚举矩形的上下边界和左边界,问题变为已知(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;
} 
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值