UVa 12265 Selling Land 解题报告(降维)

56 篇文章 0 订阅

G  Selling Land

As you may know, the country of Absurdistan is full ofabnormalities. For example, the whole country can be divided into unitsquares that are either grass or swamp. Also, the country is famousfor its incapable bureaucrats. If you want to buy a piece of land(called a parcel), you can only buy a rectangular area, because theycannot handle other shapes. The price of the parcel is determined by them and isproportional to the perimeter of the parcel, since the bureaucrats areunable to multiply integers and thus cannot calculate the area of theparcel.Per owns a parcel in Absurdistan surrounded by swamp and he wants tosell it, possibly in parts, to some buyers. When he sells arectangular part of his land, he is obliged to announce this to thelocal bureaucrats. They will first tell him the price he is supposedto sell it for. Then they will write down the name of the new ownerand the coordinates of the south-east corner of the parcel beingsold. If somebody else already owns a parcel with a south-east cornerat the same spot, the bureaucrats will deny the change of ownership.Per realizes that he can easily trick the system. He can selloverlapping areas, because bureaucrats only check whether thesouth-east corners are identical. However, nobody wants to buy aparcel containing swamp.
Figure 1: In this example, dark squares represent swamp. Per may, for example, sell three overlapping grey areas, with dimensions 2×1, 2×4 and 4×1 respectively. The total perimeter is 6 + 12 + 10=28. Note that he can get more money by selling even more land. This figure corresponds to the case in the sample input.
Now Per would like to know how many parcels of each perimeter heneeds to sell in order to maximize his profit. Can you help him? Youmay assume that he can always find a buyer for each piece of land, aslong as it doesn't contain any swamps. Also, Per is sure that nosquare within his parcel is owned by somebody else.

Input

On the first line a positive integer: the number of test cases, atmost 100. After that per test case:
  • One line with two integers n and m (1 ≤ n, m ≤ 1 000):the dimensions of Per's parcel.
  • n lines, each with m characters. Each character is either `#' or `.'. Thej-th character on the i-th line is a `#' if position (i, j)is a swamp, and `.' if it is grass. The north-west corner ofPer's parcel has coordinates (1, 1), and the south-east corner hascoordinates (n,m).

Output

Per test case:
  • Zero or more lines containing a complete list of how manyparcels of each perimeter Per needs to sell in order to maximize hisprofit. More specifically, if Per should sell pi parcels ofperimeter i in the optimal solution, output a single line"pi x i". The lines should be sorted in increasing orderof i. No two lines should have the same value of i, and you shouldnot output lines with pi=0.

Sample in- and output

InputOutput
1
6 5
..#.#
.#...
#..##
...#.
#....
#..#.
6 x 4
5 x 6
5 x 8
3 x 10
1 x 12

    题意:一个矩形中有一些点不可用,求每个点最为右下角时,矩形的最大周长,统计每个点的最大周长。

    很难说明这到底是什么类型的题目,不过看这1000×1000的图,已经100W了,基本上每个点作为右下角求其最大周长矩形只能用O(1)的复杂度了。

    常规算法,我们需要知道每个点作为右下角时,构成最大矩形的左上角在哪里。枚举的话,枚举左上角O(mn),这个矩形是否合理,即内部无不可用点,复杂度O(mn)。我们现在需要在O(1)的复杂度里搞定这些事情,也就是降维了。

    我们可以先列一下式子:矩形周长S = (矩形宽度W+矩形高度H)×2。

    首先,我们可以在O(1)的时间里,更新每个点作为右下角时,所在列的最大高度。如果上一列的高度大于当前列的高度,那么上一列的高度在当前和以后的计算中都是没有用的,可以直接删掉。我们同时就可以保持一个上升的高度栈。保存高度h的同时,我们同时保存该高度对应的合理起点p。在p列到当前列,所有列的高度都是大于等于h的。那么当前列构成的矩形周长可能会是 2×(j-p+1+h)。我们求出所有的(h - q),求出最大值即可。这个值我们同样可以保存在高度升序的栈里,维护该最大值。

    每一列在栈中最多出入栈一次,由此,每个点的复杂度都是O(1),问题解决。代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
using namespace std;

#define ff(i, n) for(int i=0;i<(n);i++)
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define dff(i, n, m) for(int i=(n);i>=(m);i--)
#define mem(a) memset((a), 0, sizeof(a))
typedef long long LL;
typedef unsigned long long ULL;
void work();

int main()
{
#ifdef ACM
    freopen("in.txt", "r", stdin);
//    freopen("in.txt", "w", stdout);
#endif // ACM

    work();
}

/*****************************************/

bool maze[1111][1111];
char str[1111];

int high[1111];

struct Node
{
    int h, p;
    int maxV;
} x, y;
Node que[1111];

int num[4444];

void work()
{
    int T;
    scanf("%d", &T);
    fff(cas, 1, T)
    {
        int n, m;
        scanf("%d%d", &n, &m);

        memset(maze, 0, sizeof(maze));
        memset(num, 0, sizeof(num));

        fff(i, 1, n)
        {
            scanf("%s", str + 1);
            fff(j, 1, m) if(str[j] == '.')
                maze[i][j] = true;
        }

        memset(high, 0, sizeof(high));
        fff(i, 1, n)
        {
            fff(j, 1, m) if(maze[i][j])
                high[j]++;
            else
                high[j] = 0;

            int bot = 0, top = -1;
            fff(j, 1, m)
            {
                x.h = high[j];
                x.p = j;
                x.maxV = x.h - x.p;

                if(x.h == 0)
                {
                    top = bot - 1;
                    continue;
                }

                while(bot <= top && que[top].h >= x.h)
                    x.p = que[top].p, x.maxV = x.h - x.p, top--;
                if(bot <= top)
                    x.maxV = max(x.maxV, que[top].maxV);

                que[++top] = x;
                int v = j+1+x.maxV;
                num[v]++;
            }
        }

        fff(i, 1, 2000) if(num[i])
            printf("%d x %d\n", num[i], i*2);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值