https://www.luogu.org/problemnew/show/P2716
给出一个n*m的矩形,求里面边长最小的正方形,使得该正方形内最大值与最小值的差大于等于给定的K。
第一反应是二分答案+二维RMQ,时间复杂度是能过的,O(nlognlognlogn),空间O(n*nlogn)。
(待补充)
考虑一个看起来不怎么优秀的O(n^3)做法,实际上是可以通过本题的。
设左上角在(i,j)的边长为k的正方形的最大值为f[i][j][k],最小值g[i][j][k],转移方程显然有f[i][j][k]=max{f[i][j][k-1],f[i+1][j][k-1],f[i][j+1][k-1],f[i+1][j+1][k-1]},g同理。
如果在顺推时找到了一个f[i][j][k]-g[i][j][k]>=K,那么这个边长k一定是最小的了,
但是这样空间受限是吃不消的,注意到转移中第三维k是单调转移的,可以用适当的转移方式(也就是正常顺推)缩掉这一维。
空间复杂度O(n^2),时间复杂度O(n^3),卡常可不开O2通过。
#include<iostream> #include<cstdio> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN=512; int n,m,q; int a[MAXN*MAXN]; int f[MAXN*MAXN],g[MAXN*MAXN]; int main(){ n=rd();m=rd();q=rd(); for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) f[(i<<9)+j]=g[(i<<9)+j]=a[(i<<9)+j]=rd(); int up=min(n,m)-1; for(register int k=1;k<=up;k++) for(register int i=1;i<=n-k;i++) for(register int j=1;j<=m-k;j++){ f[(i<<9)+j]=max(f[(i<<9)+j],max(f[(i+1<<9)+j],max(f[(i<<9)+j+1],f[(i+1<<9)+j+1]))); g[(i<<9)+j]=min(g[(i<<9)+j],min(g[(i+1<<9)+j],min(g[(i<<9)+j+1],g[(i+1<<9)+j+1]))); if(f[(i<<9)+j]-g[(i<<9)+j]>=q) return printf("%d ",k+1),0; } puts("-1"); return 0; }