[LUOGU] P2716 和谐的雪花

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\n",k+1),0;
      }
  puts("-1");
  return 0;
}

 

posted @ 2018-07-20 19:30  GhostCai  阅读(199)  评论(0编辑  收藏  举报