博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[ZJOI2007]棋盘制作 悬线法dp 求限制下的最大子矩阵
阅读量:4307 次
发布时间:2019-06-06

本文共 2361 字,大约阅读时间需要 7 分钟。

https://www.luogu.org/problemnew/show/P1169

 

第一次听说到这种dp的名称叫做悬线法,听起来好厉害

题意是求一个矩阵内的最大01交错子矩阵,开始想的是dp[2000][2000][2]维护这个位置向上向左扩充的矩阵最大长度之后n²扫一遍,但是写起来发现并不能有效的扩充,也就是状态转移方程很难写出来。

后来发现有一种奥妙重重的方法叫做悬线法,把我原本向左向上扩充的过程改为记录每一个点向左向右向上的最大长度,这些状态很显然可以通过扫一遍的方法求出来,然后对于每一个点,宽度就是l - r + 1,显然对于同一个合法区间内的点,他的left和right是相同的。

用自上而下的方法递推出到N这一行时这个点向上扩充的最大长度之后递推即可。

悬线法对一类限制下求子矩阵的问题很好用。

#include #include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;inline int read(){ int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}#define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--)#define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x)#define Sca2(x,y) scanf("%d%d",&x,&y)#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)#define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x)#define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();#define LL long long#define ULL unsigned long long #define mp make_pair#define PII pair
#define PIL pair
#define PLL pair
#define pb push_back#define fi first#define se second typedef vector
VI;const double eps = 1e-9;const int maxn = 2010;const int INF = 0x3f3f3f3f;const int mod = 1e9 + 7; int N,M,K;int Left[maxn][maxn],Right[maxn][maxn],up[maxn][maxn];int MAP[maxn][maxn];int main(){ Sca2(N,M); for(int i = 1; i <= N ; i ++){ for(int j = 1; j <= M ; j ++){ Sca(MAP[i][j]); Left[i][j] = Right[i][j] = j; up[i][j] = 1; } } for(int i = 1; i <= N ; i ++){ for(int j = 2; j <= M ; j ++){ if(MAP[i][j] != MAP[i][j - 1]){ Left[i][j] = Left[i][j - 1]; } } for(int j = M - 1; j >= 1; j --){ if(MAP[i][j] != MAP[i][j + 1]){ Right[i][j] = Right[i][j + 1]; } } } int ans1 = 0,ans2 = 0; for(int i = 1; i <= N ; i ++){ for(int j = 1; j <= M ; j ++){ if(i > 1 && MAP[i][j] != MAP[i - 1][j]){ Left[i][j] = max(Left[i][j],Left[i - 1][j]); Right[i][j] = min(Right[i][j],Right[i - 1][j]); up[i][j] = up[i - 1][j] + 1; } int a = Right[i][j] - Left[i][j] + 1; int b = min(a,up[i][j]); ans1 = max(ans1,b * b); ans2 = max(ans2,a * up[i][j]); } } Pri(ans1); Pri(ans2); return 0;}

 

转载于:https://www.cnblogs.com/Hugh-Locke/p/10261871.html

你可能感兴趣的文章
java中append()的方法
查看>>
必学高级SQL语句
查看>>
经典SQL语句大全
查看>>
log日志记录是什么
查看>>
<rich:modelPanel>标签的使用
查看>>
<h:commandLink>和<h:inputLink>的区别
查看>>
<a4j:keeyAlive>的英文介绍
查看>>
关于list对象的转化问题
查看>>
VOPO对象介绍
查看>>
suse创建的虚拟机,修改ip地址
查看>>
linux的挂载的问题,重启后就挂载就没有了
查看>>
docker原始镜像启动容器并创建Apache服务器实现反向代理
查看>>
docker容器秒死的解决办法
查看>>
管理网&业务网的一些笔记
查看>>
openstack报错解决一
查看>>
openstack报错解决二
查看>>
linux source命令
查看>>
openstack报错解决三
查看>>
乙未年年终总结
查看>>
子网掩码
查看>>