vijos 1750 建房子 单调队列

背景

安得广厦千万间,天下寒士俱欢颜。

描述

小D终于成为了一位建筑师。他的第一个任务是在一块n行m列的矩形土地上砌房子,每个房子的大小是a行b列(不能旋转)。

矩形土地的每个单元格都有一个高度。如果选定某个区域上为建房子的地方,那么需要将这个区域的每个单元格的高度变成这个区域的最小的单元格的高度,因为这样能使土地更平整。将一个单元格的高度从h2变为h1所花费的代价是h2-h1,一个区域所花费的代价为其每个单元格所花费的代价之和。

现在小D按下面所述的方式建房子:
1、首先找到矩形土地中花费最少代价就能建房子的区域(这个区域中不能有某个单元格已经砌了房子),如果有多个这样的区域,选择左上角所在行尽可能小的,如果行相同,选择列尽可能小的。

2、接下来在这块区域砌一栋房子。

3、重复上述操作,直到找不到一个可以砌房子的区域。

现在需要你告诉小D,他一共将砌多少栋房子,每栋房子的左上角的坐标,以及每栋房子所花费的代价。

格式

输入格式

输入的第一行包括四个正整数
n,m,a,b(含义如上所述)
接下来n行,每行m个非负整数
其中第i行,第j列表示第i行,第j列的单元格的高度。

输出格式

输出第一行为一个非负整数S:表示一共砌了多少栋房子
接下来S行
每行三个整数i,j,v:表示第S个房子的左上角的所在行,所在列,以及所花费的代价。

  输入
5 5 2 2
9 9 4 4 10 
10 3 3 9 3 
3 6 3 8 1 
4 2 10 9 8 
7 10 10 3 5 

输出
4
2 2 3
4 4 13
1 4 14
4 1 15

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 using namespace std;
 7 
 8 int   map[1004][1004],vis[1004][1004];
 9 long long are[1004][1004];
10 int min_1[1004][1004],min_2[1004][1004];
11 int  sk[1004];
12 
13 struct date
14 {
15     int  i,j;
16     bool fell;
17     long long val;
18 }temp,cnt[1111111];
19 
20 bool cmp( const date &a,const date &b )
21 {
22     if( a.val != b. val ) return a.val< b.val;
23     else if( a.i != b.i ) return a.i  < b.i;
24                           return a.j  < b.j;
25 }
26 int main( )
27 {
28     int i,j,k,l,N,M,A,B,top,hid;
29     long long res;
30     while( scanf("%d%d%d%d",&N,&M,&A,&B) != EOF )
31     {
32         memset( map,0,sizeof(map) );
33         memset( vis,0,sizeof(vis) );
34         for( i = 1; i <= N; i++ )
35         for( j = 1; j <= M; j++ )
36         {
37             scanf("%d",&map[i][j]);
38             are[i][j] = are[i-1][j] + are[i][j-1] + map[i][j] - are[i-1][j-1];
39         }
40 
41         for( i = 1; i <= N; i++ )
42         {
43             top = hid = 1;  sk[top] = 1; min_1[i][1] = map[i][1];
44             for( j = 2; j <= M; j++ )
45             {
46                 while( top >= hid && sk[hid] + B <= j ) hid++;
47                 while( top >= hid && map[i][sk[top]] >= map[i][j] ) top--;
48                 sk[++top] = j;
49                 min_1[i][j] = map[i][sk[hid]];
50             }
51         }
52         for( i = 1; i <= M; i++ )
53         {
54             top = hid = 1; sk[top] = 1; min_2[1][i] = min_1[1][i];
55             for( j = 2; j <= N; j++ )
56             {
57                 while( top >= hid && sk[hid] + A <= j ) hid++;
58                 while( top >= hid && min_1[sk[top]][i] >= min_1[j][i] ) top--;
59                 sk[++top] = j;
60                 min_2[j][i] = min_1[sk[hid]][i];
61             }
62         }
63         k = 1;
64         for( i = A; i <= N; i++ )
65         for( j = B; j <= M; j++ )
66         {
67             cnt[k].val = are[i][j]-are[i-A][j]-are[i][j-B]+are[i-A][j-B]-( long long )min_2[i][j]*A*B;
68             cnt[k].i = i;
69             cnt[k++].j = j;
70         }
71         sort( &cnt[1],&cnt[1]+k-1,cmp );
72         int x = 0;
73         for( i = 1; i < k; i++ )
74         {
75             int a = cnt[i].i,b = cnt[i].j,c = a-A+1,d = b-B+1;
76             cnt[i].val =  cnt[i].val,cnt[i].i   =  cnt[i].i-A+1,cnt[i].j =  cnt[i].j-B+1;
77             if( vis[a][b] + vis[a][d] + vis[c][b] + vis[c][d] == 0 )
78             {
79                cnt[i].fell = true;x++;
80                for( j = d; j <= b; j++ )
81                for( l = c; l <= a; l++ )
82                     vis[l][j] = 1;
83             }
84             else cnt[i].fell = false;
85         }
86         printf("%d\n",x);
87         for( i = 1; i < k; i++ )
88         if( cnt[i].fell )
89         printf("%d %d %I64d\n",cnt[i].i,cnt[i].j,cnt[i].val);
90     }
91     return 0;
92 }

 

posted on 2013-03-11 22:33  浪舟  阅读(219)  评论(0编辑  收藏  举报

导航