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);
}