P3117 [USACO15JAN] 尺取法

题意

传送门 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 ll,可以使用尺取法将复杂度降为 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值