POJ 2082 题解

Terrible Sets

Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 5330   Accepted: 2715

Description

Let N be the set of all natural numbers {0 , 1 , 2 , . . . }, and R be the set of all real numbers. wi, hi for i = 1 . . . n are some elements in N, and w0 = 0. 
Define set B = {< x, y > | x, y ∈ R and there exists an index i > 0 such that 0 <= y <= hi ,∑0<=j<=i-1wj <= x <= ∑0<=j<=iwj} 
Again, define set S = {A| A = WH for some W , H ∈ R+ and there exists x0, y0 in N such that the set T = { < x , y > | x, y ∈ R and x0 <= x <= x0 +W and y0 <= y <= y0 + H} is contained in set B}. 
Your mission now. What is Max(S)? 
Wow, it looks like a terrible problem. Problems that appear to be terrible are sometimes actually easy. 
But for this one, believe me, it‘s difficult.

Input

The input consists of several test cases. For each case, n is given in a single line, and then followed by n lines, each containing wi and hi separated by a single space. The last line of the input is an single integer -1, indicating the end of input. You may assume that 1 <= n <= 50000 and w1h1+w2h2+...+wnhn < 109.

Output

Simply output Max(S) in a single line for each case.

Sample Input

3
1 2
3 4
1 2
3
3 4
1 2
3 4
-1

Sample Output

12
14

Source

Shanghai 2004 Preliminary

题意:给一排高度不同底部在同一水平线的连续矩形,在形成的总区域内寻找面积最大的矩形子区域。

思路一:枚举答案区域的最高点,也就是遍历所有小矩形,并以当前小矩形的高度为最终高度,找到左右方向课扩展的最大范围即可,复杂度n^2。因为太暴力了,没有写,据说可以过...

思路二:优化一下思路一,在寻找最大可扩展边界时,因为可扩展性是单调的,所以我们可以二分区间端点然后用某种数据结构求出区间最小值即可。我是二分+线段树,复杂度n*log^2。TLE了。

  1 #include <iostream>
  2 #include <fstream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <string>
  8 #include <cstring>
  9 #include <algorithm>
 10 #include <queue>
 11 #include <stack>
 12 #include <vector>
 13 #include <set>
 14 #include <map>
 15 #include <list>
 16 #include <iomanip>
 17 #include <cctype>
 18 #include <cassert>
 19 #include <bitset>
 20 #include <ctime>
 21
 22 using namespace std;
 23
 24 #define pau system("pause")
 25 #define ll long long
 26 #define pii pair<int, int>
 27 #define pb push_back
 28 #define mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43
 44 int n;
 45 struct rec {
 46     ll w;
 47     int h;
 48 } R[50015];
 49 int mi[200015];
 50 void pushup(int i) {mi[i] = min(mi[i << 1], mi[i << 1 | 1]);}
 51 void build(int i, int l, int r) {
 52     if (l == r) {
 53         mi[i] = R[l].h;
 54         return;
 55     }
 56     int mi = l + r >> 1;
 57     build(i << 1, l, mi);
 58     build(i << 1 | 1, mi + 1, r);
 59     pushup(i);
 60 }
 61 int query(int i, int l, int r, int x, int y) {
 62     if (x <= l && r <= y) {
 63         return mi[i];
 64     }
 65     int res1 = MOD, res2 = MOD, mi = l + r >> 1;
 66     if (x <= mi) res1 = query(i << 1, l, mi, x, y);
 67     if (mi < y) res2 = query(i << 1 | 1, mi + 1, r, x, y);
 68     return min(res1, res2);
 69 }
 70 int main() {
 71     R[0].w = 0, R[0].h = -1;
 72     while (~scanf("%d", &n) && ~n) {
 73         ll ans = 0;
 74         for (int i = 1; i <= n; ++i) {
 75             scanf("%lld%d", &R[i].w, &R[i].h);
 76             R[i].w += R[i - 1].w;
 77         }
 78         build(1, 0, n);
 79         for (int i = 1; i <= n; ++i) {
 80             int s1 = 0, e1 = i - 1, m1, res1 = i;
 81             while (s1 <= e1) {
 82                 m1 = s1 + e1 >> 1;
 83                 if (query(1, 0, n, m1, i - 1) < R[i].h) {
 84                     s1 = m1 + 1;
 85                 } else {
 86                     e1 = (res1 = m1) - 1;
 87                 }
 88             }
 89             int s2 = i + 1, e2 = n, m2, res2 = i;
 90             while (s2 <= e2) {
 91                 m2 = s2 + e2 >> 1;
 92                 if (query(1, 0, n, i + 1, m2) < R[i].h) {
 93                     e2 = m2 - 1;
 94                 } else {
 95                     s2 = (res2 = m2) + 1;
 96                 }
 97             }
 98             ans = max(ans, R[i].h * (R[res2].w - R[res1 - 1].w));
 99         }
100         printf("%lld\n", ans);
101     }
102     return 0;
103 }

思路三:维护一个高度递增的单调栈,每次新加入矩形时,弹出所有高度比他大的矩形同时求出弹出范围矩形所能形成的最大值。维护结束后再枚举栈内元素作为矩形区域左端点即可。复杂度O(n)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21
22 using namespace std;
23
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43
44 struct rec {
45     int w;
46     int h;
47 } R[50015];
48 int n;
49 stack<int> sta;
50 int main() {
51     R[0].w = 0, R[0].h = -1;
52     sta.push(0);
53     while (~scanf("%d", &n) && ~n) {
54         for (int i = 1; i <= n; ++i) {
55             scanf("%d%d", &R[i].w, &R[i].h);
56             R[i].w += R[i - 1].w;
57         }
58         int ans = 0;
59         for (int i = 1; i <= n; ++i) {
60             int we = R[i - 1].w;
61             while (R[sta.top()].h >= R[i].h) {
62                 int x = sta.top();
63                 sta.pop();
64                 int y = sta.top();
65                 ans = max(ans, R[x].h * (we - R[y].w));
66             }
67             int x = sta.top();
68             ans = max(ans, R[i].h * (R[i].w - R[x].w));
69             sta.push(i);
70         }
71         int we = R[sta.top()].w;
72         while (sta.size() > 1) {
73             int x = sta.top();
74             sta.pop();
75             int y = sta.top();
76             ans = max(ans, R[x].h * (we - R[y].w));
77         }
78         printf("%d\n", ans);
79     }
80     return 0;
81 }

原文地址:https://www.cnblogs.com/BIGTOM/p/8468083.html

时间: 2024-10-18 16:16:56

POJ 2082 题解的相关文章

poj 2082 Terrible Sets (数据结构 ——栈 STL)

 Terrible Sets Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 2999   Accepted: 1549 Description Let N be the set of all natural numbers {0 , 1 , 2 , . . . }, and R be the set of all real numbers. wi, hi for i = 1 . . . n are some elem

计算最大矩形面积,POJ(2082)

题目链接:http://poj.org/problem?id=2082 把矩形按照高度一次递增的循序排列,当违反这一规则的时候,更新ans,用新的data替换之前的矩形.然后最后扫一遍. #include <iostream> #include <stack> #include <cstdio> using namespace std; struct rec { int w; ///宽 int h; ///高 } data; int main() { int n; wh

stack(单调栈) POJ 2082 Terrible Sets

题目传送门 题意:紧贴x轴有一些挨着的矩形,给出每个矩形的长宽,问能组成的最大矩形面积为多少 分析:用堆栈来维护高度递增的矩形,遇到高度小的,弹出顶部矩形直到符合递增,顺便计算矩形面积,且将弹出的宽度都累积到当前的矩形中,这样最后再扫描一遍,算面积很方便,这题应该算是 POJ 2559 的强化版了 收获:stack的应用,求矩形面积,矩阵相乘,表达式计算 代码: /************************************************ * Author :Running

poj - 3641 题解

题意:检验一个数是否是质数,且满足ap = a (mod p) 题解:快速幂,质数检验 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 long long power(long long a,long long b,long long c) 7 { 8 long long res,t; 9 res=

poj - 3070 题解

题意:斐波那契数列的矩阵链乘求法. 题解:快速幂优化矩阵链乘解决. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 struct datatype 7 { 8 int a[2][2]; 9 }; 10 datatype multiple(datatype x,datatype y) 11 { 1

poj 1066 题解

题意:求从正方体外面到达这个黑点所需穿过的最少线段数(规定只能从线段中点穿过,包括最外层的墙),共有n面墙 0 <= n <= 30 题解:事实上枚举边界上的中点,判断它和黑点的线段与这些墙的交点数即可 解释:注意到,墙这一长线段相对于黑点连线,等价于直线--无论是在实现上还是题意上.连线若与墙相交,则黑点与枚举点必在墙两侧,无可避免地要穿过这面墙,至于从线段中点穿过在本题中是没有意义的.起始点选取本该在线段中点,但显然选取两个端点的最小值不会比它差,而一个端点的结果不会比相邻的两个中点结果好

poj 1556 题解

题意:如图,大概猜的到了?最多18面墙,每面墙上两个门,从(0,5)走到(10,5)的最短距离,保留两位小数 题解:这道题非常贴心地按序给出墙的坐标,把每个端点当做图里面的一个节点,用O(n3)时间判断每两点之间是否能连边,判断方法为判断直线与线段是否相交(事实上是两个线段,但在这道题里面用直线交线段即可),跑一个最短路即可(既然已经到了三次方级别,干脆写了最短的Floyd) #include<cmath> #include<cstdio> #include<cstring&

poj - 1002题解

题意:给定一个字符串,按一定格式处理后排序并输出 题解:转换成7位数字来处理即可,输出的时候注意格式. 1 #include<iostream> 2 #include<algorithm> 3 #include<string> 4 using namespace std; 5 long a[100001]; 6 bool com(const int &x,const int&y) 7 { 8 return x<y; 9 } 10 int main(

poj 2826 题解

题意:给出两条线段的位置(可相交),用它们来接落下来的雨水,问最终储水量是多少 题解:基本思路是求出两条线段交点,然后计算在交点上方部分三角形(短板效应,大小由较小的y确定)的面积即可. 注意点:事实上这个问题是判定+计算,要判定能不能接到水,再进行计算. 判定①:线段不相交或平行,则接不到水 判定②:以交点为起点的两条向上的两条线段中,一条线段完全挡住了另一条线段,则接不到水 由于存在判定,所以会出现精度问题,要注意eps的使用 实现: ①每条线段被交点分成两部分,用(1,0)×线段,选取结果