【BZOJ5085】最大 鸽巢原理

【BZOJ5085】最大

Description

给你一个n×m的矩形,要你找一个子矩形,价值为左上角左下角右上角右下角这四个数的最小值,要你最大化矩形的价值。

Input

第一行两个数n,m,接下来n行每行m个数,用来描述矩形
n, m ≤ 1000

Output

输出一个数表示答案

Sample Input

2 2
1 2
3 4

Sample Output

1

题解:我们先将所有数排序,然后从大到小扔到矩形中。每当我们加入一个点时,我们枚举它能和同行中的所有点形成的点对。比如有一行有两个点(x1,y1)和(x1,y2),那么就形成了一个点对(y1,y2)。那么一旦某个点对出现了两次,则说明出现了一个矩形。那么我们就不断扔,直到出现某个重复的点对为止,时间复杂度$O(n^2log_n)$。

然而似乎有个结论,答案一定在最大的4*n个点之中。那么取出这些点暴力即可。如果用nth_element+如上做法的话,时间复杂度可以从$O(16*n^2)$优化到$O(n^2)$(然而并不想卡这个常数)。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n,m,tot;
struct node
{
	int x,y,val;
}p[1000010];
int map[1010][1010];
vector<int> v[1010];
vector<int>::iterator it;
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
bool cmp(const node &a,const node &b)
{
	return a.val>b.val;
}
int main()
{
	n=rd(),m=rd();
	int i,j;
	for(i=1;i<=n;i++)	for(j=1;j<=m;j++)	p[++tot].x=i,p[tot].y=j,p[tot].val=rd();
	sort(p+1,p+n*m+1,cmp);
	for(i=1;i<=tot;i++)
	{
		for(it=v[p[i].x].begin();it!=v[p[i].x].end();it++)
		{
			if(map[p[i].y][*it])
			{
				printf("%d",p[i].val);
				return 0;
			}
			map[p[i].y][*it]=map[*it][p[i].y]=1;
		}
		v[p[i].x].push_back(p[i].y);
	}
}
原文地址:https://www.cnblogs.com/CQzhangyu/p/7886896.html