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.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
Input | Output |
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);
}
}