题意
传送门 P3117 [USACO15JAN]Cow Rectangles
题解
暴力枚举矩形端点 O ( N 4 ) O(N^4) O(N4)。枚举矩形上下界,考虑区间 [ l , r ) [l,r) [l,r),假设区间代表的矩形内 H o l s t e i n s Holsteins Holsteins 奶牛数为 n n n 且对于右界 r r r 而言是最大值,那么对于满足区间 H o l s t e i n s Holsteins Holsteins 奶牛数不小于 n n n 的 [ l ′ , r + 1 ) [l',r+1) [l′,r+1) 的左界满足 l ′ ≥ l l'\geq l l′≥l,可以使用尺取法将复杂度降为 O ( n 3 ) O(n^3) O(n3)。
预处理纵向的前缀和,可以 O ( 1 ) O(1) O(1) 求出对于某一上下界单位宽度的奶牛数量。若区间右侧 G u e r n s e y s Guernseys Guernseys 奶牛数量为 0 0 0 则右端点前移,对于固定的右端点,前移左端点使奶牛数量不变且区间长度最小。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define maxn 505
int N, X[maxn], Y[maxn], mpx[maxn], mpy[maxn], H[maxn][maxn], G[maxn][maxn];
char T[maxn];
int compress(int *x, int *mpx, int n)
{
vector<int> xs(n);
for (int i = 0; i < n; i++)
{
xs[i] = x[i];
}
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(), xs.end()), xs.end());
for (int i = 0; i < n; i++)
{
int sx = lower_bound(xs.begin(), xs.end(), x[i]) - xs.begin();
mpx[sx] = x[i], x[i] = sx;
}
return xs.size();
}
int main()
{
scanf("%d", &N);
for (int i = 0; i < N; i++)
{
scanf("%d%d %c", X + i, Y + i, T + i);
}
int h = compress(X, mpx, N);
int w = compress(Y, mpy, N);
for (int i = 0; i < N; i++)
{
T[i] == 'H' ? ++H[X[i] + 1][Y[i]] : ++G[X[i] + 1][Y[i]];
}
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
H[i + 1][j] += H[i][j];
G[i + 1][j] += G[i][j];
}
}
int num = -1, area = -1;
for (int i = 0; i < h; ++i)
{
for (int j = h; j > i; --j)
{
if (num >= (mpx[j - 1] - mpx[i] + 1) * (mpy[w - 1] - mpy[0] + 1))
{
break;
}
int l = 0, r = 0, n = 0;
for (;;)
{
bool f = 0;
while (r < w && G[j][r] - G[i][r] > 0)
{
f = 1, ++r;
}
if (r >= w)
{
break;
}
n = f ? H[j][r] - H[i][r] : n + H[j][r] - H[i][r], l = f ? r : l;
++r;
while (l + 1 < r && H[j][l] - H[i][l] == 0)
{
++l;
}
int s = (mpx[j - 1] - mpx[i]) * (mpy[r - 1] - mpy[l]);
if (n > num || (n == num && s < area))
{
num = n, area = s;
}
}
}
}
printf("%d\n%d\n", num, area);
return 0;
}