一道不太明显的dp,dp[i][j]的含义是,以i,j为右下角的福字的大小。
首先进行预处理,两个二维数组。shang[i][j]表示从坐标ij的元素开始向上寻找,能找到多少个元素使他们都满足map[i-1][j] + 1 == map[i][j],比如这个
1 2 3
2 3 4
3 5 5
他的shang数组就是
1 1 1
2 2 2
3 3 3
同理,再构建一个左数组。
然后我们就可以找到这样的转移方程
if(map[i][j] == map[i-1][j-1] + 2){
dp[i][j] = min(dp[i-1][j-1]+1,min(shang[i][j],zuo[i][j]));
}
ac代码
#include <iostream>
#include <math.h>
#include <iomanip>
#include <string>
#include <cstdio>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#define INF 0x3f3f3f3f
#define N 2010
#define M 998244353
#define ll long long
using namespace std;
int n;
int map[N][N];
int shang[N][N],zuo[N][N];
int dp[N][N];
int main() {
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%d",&map[i][j]);
}
}
int tmp = 1;
for(i=1;i<=n;i++){
tmp = 1;
zuo[i][1] = tmp;
for(j=2;j<=n;j++){
if(map[i][j] == map[i][j-1] + 1){
tmp++;
zuo[i][j] = tmp;
}else{
tmp = 1;
zuo[i][j] = tmp;
}
}
}
for(j=1;j<=n;j++){
tmp = 1;
shang[1][j] = tmp;
for(i=2;i<=n;i++){
if(map[i][j] == map[i-1][j] + 1){
tmp++;
shang[i][j] = tmp;
}else{
tmp = 1;
shang[i][j] = tmp;
}
}
}
for(i=1;i<=n;i++){
dp[i][1] = dp[1][i] = 1;
}
int ans = 0;
for(i=2;i<=n;i++){
for(j=2;j<=n;j++){
if(map[i][j] == map[i-1][j-1] + 2){
dp[i][j] = min(dp[i-1][j-1]+1,min(shang[i][j],zuo[i][j]));
ans = max(ans,dp[i][j]);
}else
{
dp[i][j] = 1;
ans = max(ans,dp[i][j]);
}
}
}
printf("%d\n",ans);
return 0;
}
一开始想的是按照dp[i-1][j]或者dp[i][j-1]构造转移方程,后来发现很麻烦而且没有必要。
这道题的数据比较松,有些错误的转移方程也可以跑过。