BZOJ 5085 最大
2017.11.24
2017.11.24
给你一个$N \times M$的矩形,要你找一个子矩形,价值为左上角左下角右上角右下角这四个数的最小值,要你最大化矩形的价值。
神题啊……
考虑二分答案。对于一个答案我们可以把整个矩形转化成01矩阵,之后目的就是选出一个四个角都是1的矩阵。
之后就不会了……
求一个这样的矩阵其实就是求两条水平方向上的平行线段。实际上暴力就可以解决问题。
因为这样的线段最多只有$M^2$个,而且只要发生冲突出现两个就出解了……所以直接暴力的复杂度是正确的。
应用了从答案入手的反向思考的思想。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1010
int n,m,v[N][N],pos[N][N],cnt[N],res[N*N*2],minn=0x3f3f3f3f,maxn=0xefefefef;
inline int RI()
{
int ret=0,mus=1;char tmp=getchar();
while(tmp<'0'||tmp>'9')
{
if(tmp=='-') mus=-1;
tmp=getchar();
}
while(tmp>='0'&&tmp<='9') ret=ret*10+tmp-'0',tmp=getchar();
return ret*mus;
}
bool check(int tg)
{
memset(cnt,0,sizeof cnt);
memset(res,0,sizeof res);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(v[i][j]>=tg) pos[i][++cnt[i]]=j;
for(int i=1;i<=n;++i)
for(int j=1;j<=cnt[i];++j)
for(int k=1;k<=cnt[i];++k)
if(j!=k)
{
if(res[pos[i][j]*n+pos[i][k]]) return true;
res[pos[i][j]*n+pos[i][k]]++;
}
return false;
}
int bisection()
{
int l=minn,r=maxn+1,mid;
while(l<r)
{
mid=(l+r)>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
return l-1;
}
int main()
{
n=RI(),m=RI();
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
v[i][j]=RI();
minn=min(minn,v[i][j]),maxn=max(maxn,v[i][j]);
}
printf("%d\n",bisection());
return 0;
}