好吧,我知道我很久没单独写题解了。
Description
不但奶牛想建造房子,作为一名建筑师的Bob也想建造自己的房子。他买了块土地,问题是土地的地形不平整。
这块土地的形状就像一个矩形,长N米,宽M米。我们将它看作是由N×M个小正方形组成。(见图) Bob的房子的形状也是矩形的,其边和土地的边是平行的,而且其顶点与某个小正方形的顶点重合。为了使房子保持平衡,Bob要选具有相同高度的小方格建造房子。
(土地被分成多个小方格。房屋的两个可能建造的位置如右图有红色和蓝色。)
请计算Bob建造房子的方案数。
Input
第 1 行输入包含N和M;
接下来的N行,每行包含M个整数A[i][j],表示该方格的土地高度。
Output
输出共一行一个整数,即任务中所需的答案。
Sample Input
【输入样例1】
5 3
2 2 2
2 2 1
1 1 1
2 1 2
1 2 1
【输入样例2】
4 3
1 1 1
1 1 1
2 2 2
2 2 2
Sample Output
【输出样例1】
27
【输出样例2】
36
Data Constraint
对于10%的数据: 1≤N,M≤50;1≤A[i][j]≤10;
对于30%的数据: 1≤N,M≤500;1≤A[i][j]≤10,000;
对于100%的数据:1≤N,M≤1,000;1≤A[i][j]≤1,000,000,000;
题解
听说正解是什么单调栈,只是吓人的,其实很简单。
对于每一位,维护up[i,j]表示这一列从上开始,有几个连续的与本位相同的数(持续至本位,包括本身,即初值为1)。那么对于一行的up[i]来说,我们再开一个栈来维护从前到目前连续的区间内,相应的矩形个数,举个例子:
额,有点丑,将就着看。
那么假设这些都是同一颜色的,我们做到3、5、9、12、16这一行,1、6号方块是没用的,那么我们可以直接删去,即最终处理出来的栈为2,2,3,3,4。
接着我们要压栈,大概就是将它压成
原数 个数
2 2
3 2
4 1
记得当颜色不一样时整个栈清零。
每次做一位统计一位。
var
n,m,i,j,k,tot:longint;
ans,jl:int64;
up,a:array[0..1000,0..1000]of longint;
z:array[0..1000,1..2]of longint;
begin
readln(n,m);
for i:=1 to n do
begin
for j:=1 to m do
begin
read(a[i,j]);
up[i,j]:=1;
if a[i,j]=a[i-1,j] then
inc(up[i,j],up[i-1,j]);
if j=1 then
begin
fillchar(z,sizeof(z),0);
tot:=1;
z[tot,1]:=up[i,j];
z[tot,2]:=1;
inc(ans,up[i,j]);
continue;
end;
if a[i,j]<>a[i,j-1] then
begin
fillchar(z,sizeof(z),0);
tot:=1;
z[tot,1]:=up[i,j];
z[tot,2]:=1;
inc(ans,up[i,j]);
continue;
end;
if up[i,j]<z[tot,1] then
begin
jl:=1;
for k:=tot downto 1 do
begin
if up[i,j]>=z[k,1] then
break;
inc(jl,z[k,2]);
end;
if up[i,j]<z[1,1] then
begin
tot:=1;
z[tot,1]:=up[i,j];
z[tot,2]:=jl;
end
else
begin
if up[i,j]=z[k,1] then
begin
tot:=k;
inc(z[tot,2],jl);
end
else
begin
tot:=k+1;
z[tot,1]:=up[i,j];
z[tot,2]:=jl;
end;
end;
for k:=1 to tot do
inc(ans,z[k,1]*z[k,2]);
continue;
end;
if up[i,j]=z[tot,1] then
inc(z[tot,2])
else
begin
inc(tot);
z[tot,1]:=up[i,j];
z[tot,2]:=1;
end;
for k:=1 to tot do
inc(ans,z[k,1]*z[k,2]);
end;
readln;
end;
writeln(ans);
end.