Nowcoder9986E.网格(线性DP)

E.网格

题意:

给出一个n*m的网格,每个位置需要从上下左右四个方向中选择垂直的两个。

定义w(x)=x+x的二进制形式的1的数量。

如果两个相邻位置互相在对方选择的方向上,则对答案产生\(a_1\ xor\ a_2\)的贡献。

询问最大答案。

题解:

关注垂直这个性质。

行和列其实是独立考虑的,分别线性DP出行列的答案加起来即可。

// Problem: 网格
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/9986/E
// Memory Limit: 524288 MB
// Time Limit: 6000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//每个点有六种状态
//即每条边有个边权
//每个点可以选择自己周围的两条边


#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
int n,m;
int a[maxn][maxn];
int f[maxn][maxn][2];//第i行第j个点选上/下 左/右
int cal (int x) {
	int ans=x;
	while (x) {
		ans+=x%2;
		x/=2;
	}
	return ans;
}
int main () {
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
	int ans=0;
	for (int i=1;i<=n;i++) {
		for (int j=2;j<=m;j++) {
			f[i][j][0]=max(f[i][j-1][0],f[i][j-1][1]+cal(a[i][j]^a[i][j-1]));
			f[i][j][1]=max(f[i][j-1][1],f[i][j-1][0]);
		}
		ans+=max(f[i][m][0],f[i][m][1]);
	}
	memset(f,0,sizeof(f));
	for (int j=1;j<=m;j++) {
		for (int i=2;i<=n;i++) {
			f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]+cal(a[i][j]^a[i-1][j]));
			f[i][j][1]=max(f[i-1][j][1],f[i-1][j][0]);
		}
		ans+=max(f[n][j][0],f[n][j][1]);
	}
	printf("%d\n",ans);
}
posted @ 2021-03-12 00:35  zlc0405  阅读(162)  评论(0编辑  收藏  举报