您的位置:首页 > 其它

【2017.11.25普及组模拟】Bob

2017-11-30 12:26 856 查看

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;

Solution

最先想到的方法是无法得到任何分数的n^3*m^3的方法。

但是,我们发现这题是可以用单调队列的。

我们首先找到每个点可以向上跟他相同的个数。

我们可以发现这样就会是一个这样的图形(对于一行来说):



假设我们这一行搜到了第2个,很明显以当前(2,1)这一个为右下角,我们可行的左下角有(1,4),(1,3),(1,2),(1,1),(2,3),(2,2),(2,1)。也就是说,以(2,1)为右下角得到的贡献就是7。

再看(3,1),我们以当前这个点为右下角,会发现(1,4)是不可以做他的左上角的,因为中间缺了一块,那么说明,当我们发现第二列比第一列要小的时候,我们所能够加的就少了,也就是少了之前所有比他高的高度。我们可以用一个单调队列,记录下这些高度,然后当我们发现比上一个低的话就往前找所有比他小的,下一次就少加这么多,并每次把比他高的改成和他一样。

每一行都这么做,就好了。

#include<cstdio>
#include<iostream>
using namespace std;
long long high[1010][1010];
long long num[1010][1010];
long long n,m,t;
long long sum,ans;
long long d[1010];
int main()
{
freopen("bob.in","r",stdin);
freopen("bob.out","w",stdout);
scanf("%lld%lld",&n,&m);
int i,j,k;
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
scanf("%lld",&high[i][j]);
for (i=1;i<=n;++i)
for (j=1;j<=m;++j)
{
num[i][j]=1;
if(high[i][j]==high[i-1][j]) num[i][j]+=num[i-1][j];
}
ans=0;
for (i=1;i<=n;++i)
{
t=sum=0;
for (j=1;j<=m;++j)
{
if(high[i][j]!=high[i][j-1]) t=sum=0;
d[++t]=num[i][j];
sum+=num[i][j];
k=t-1;
while(k>0&&d[k]>d[t])
{
sum-=(d[k]-d[t]);
d[k]=d[t];
k--;
}
ans+=sum;
}
}
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: