【BZOJ】3039: 玉蟾宫(DP/单调栈)
http://www.lydsy.com/JudgeOnline/problem.php?id=3039

每次看到我的提交都有点淡淡的忧伤T_T。。
看到此题我想到用前缀和维护点ij向左和向上能拓展的最大长度,然后设状态f(i, j, 0)表示ij这个点为最大矩形的右下角时的长(横的),f(i, j, 1)表示ij这个店为最大矩形右下角时的宽(竖的),然后决策就是取点(i-1, j-1)的f值拓展一层为ij的,找到一个可行最大解。
过了几个样例我以为就能过了0.0没有认真考虑,,所以造成了前面2个wa。。原因很简单,此方程不满足最优子结构,因为你在拓展最大矩形的时候,不能保证(i+1, j+1)用到自己使得矩形增大,比如
0 0 0 1 1 0
1 1 1 1 1 0
0 0 0 1 1 0
当到点3,5的时候(下标从1开始),用到的是2,4,而2,4的最优解是向左拓展到2,1,因此方程转移后得到的是一个面积为4的矩形,与最优面积为6的矩形相悖,所以这样设是错误的。
看了题解。。。嗯。。我这个方法其实是能用的,只不过换了一点和换了方程。
我们设l[x][y]表示xy这个点向左能拓展到的最远的下标再-1,r[x][y]表示xy这个点想右能拓展到的最远的位置再+1,根据矩形面积低×高,我们只需要将高算出来,找到一个恰当的底,那么面积就求出来了。
首先我们还得维护2个数组,L[x][y]表示xy所构成的最大矩形的底的最左边的点的位置,R[x][y]表示底最右边的点的位置。接下来就是转移了~
l和r很好求,现在我们要求的是L和R,xy的最大面积=(R[x][y]-L[x][y]+1)×高,高可以通过转移时一步步获得,R[x][y]=min(r[x][y]-1, R[x-1][y]),L[x][y]=max(l[x][y]+1, L[x-1][y]),这里取max和min应该很好理解,嗯~此步骤就能看出我之前做法的不足了~这样做是同方向的,所以底是最优的,而高显然是最优的,所以矩形面积显然是最优的。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define for1(i,a,n) for(i=a;i<=n;++i)
#define for2(i,a,n) for(i=a;i<n;++i)
#define for3(i,a,n) for(i=a;i>=n;--i)
#define for4(i,a,n) for(i=a;i>n;--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define read(a) scanf("%d", &a)
#define print(a) printf("%d", a)
inline int getnum() { int ret=0; char c; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0' && c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; } const int N=1005;
int imap[N][N], l[N][N], r[N][N], L[N][N], R[N][N], h[N][N]; int main() {
int n, m, c, ans=0;
n=getnum(); m=getnum();
int i, j, t;
for1(i, 1, n) for1(j, 1, m) {
for(c=getchar(); c!='R' && c!='F'; c=getchar());
if(c=='F') imap[i][j]=1;
}
for1(i, 1, n) {
t=0;
for1(j, 1, m)
if(imap[i][j]) l[i][j]=t;
else L[i][j]=0, t=j;
t=m+1;
for3(j, m, 1)
if(imap[i][j]) r[i][j]=t;
else R[i][j]=m+1, t=j;
}
for1(j, 0, m+1) R[0][j]=m+1;
for1(i, 1, n) for1(j, 1, m)
if(imap[i][j]) {
h[i][j]=h[i-1][j]+1;
L[i][j]=max(l[i][j]+1, L[i-1][j]);
R[i][j]=min(r[i][j]-1, R[i-1][j]);
ans=max((R[i][j]-L[i][j]+1)*h[i][j], ans);
}
print(ans*3);
return 0;
}
然后是单调栈的做法,假设只有i为底的一个点的高比i+!为底的一个点的高,那么i所在的底只有长度为1,而i+1所在底的长度为2,满足单调性,即高度越高,比他矮的都能够len+1,所以可以用单调栈实现。
(看了hzwer神犇的题解后才懂的)
我们维护a[i][j]表示ij点向上拓展的最长长度,那么在i这一条底上,我们将所有的高进行单调栈处理,然后更新ans即可。(图都不用存了)
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
#define for1(i,a,n) for(i=a;i<=n;++i)
#define for2(i,a,n) for(i=a;i<n;++i)
#define for3(i,a,n) for(i=a;i>=n;--i)
#define for4(i,a,n) for(i=a;i>n;--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define read(a) scanf("%d", &a)
#define print(a) printf("%d", a)
inline int getnum() { int ret=0; char c; for(c=getchar(); c<'0' || c>'9'; c=getchar()); for(; c>='0' && c<='9'; c=getchar()) ret=ret*10+c-'0'; return ret; } const int N=1005;
int n, m, sum[N][N], s[N], l[N], ans, top; void update(int h[]) {
int len;
top=0; l[top]=s[top]=0;
for(int i=1; i<=m; ++i) {
if(h[i]>=s[top]) s[++top]=h[i], l[top]=1;
else {
len=0;
while(top && s[top]>h[i]) {
len+=l[top];
ans=max(ans, s[top]*len);
top--;
}
s[++top]=h[i]; l[top]=len+1;
}
}
len=0;
while(top) {
len+=l[top];
ans=max(ans, s[top]*len);
top--;
}
} int main() {
int c;
n=getnum(); m=getnum();
int i, j;
for1(i, 1, n) for1(j, 1, m) {
for(c=getchar(); c!='R' && c!='F'; c=getchar());
if(c=='F') sum[i][j]=sum[i-1][j]+1;
}
for1(i, 1, n) update(sum[i]);
print(ans*3);
return 0;
}
Description
有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。
这片土地被分成N*M个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。
现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着'F'并且面积最大。
但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你S两银子。
Input
第一行两个整数N,M,表示矩形土地有N行M列。
接下来N行,每行M个用空格隔开的字符'F'或'R',描述了矩形土地。
Output
输出一个整数,表示你能得到多少银子,即(3*最大'F'矩形土地面积)的值。
Sample Input
R F F F F F
F F F F F F
R R R F F F
F F F F F F
F F F F F F
Sample Output
HINT
对于50%的数据,1<=N,M<=200
对于100%的数据,1<=N,M<=1000
Source
【BZOJ】3039: 玉蟾宫(DP/单调栈)的更多相关文章
- bzoj 3039: 玉蟾宫 单调栈或者悬线法求最大子矩阵和
3039: 玉蟾宫 Time Limit: 2 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 有一天,小猫rainbow ...
- BZOJ 3039: 玉蟾宫
3039: 玉蟾宫 Description 有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地. 这片土地被分成N*M个格子,每个 ...
- BZOJ 3039: 玉蟾宫( 悬线法 )
最大子矩阵...悬线法..时间复杂度O(nm) 悬线法就是记录一个H向上延伸的最大长度(悬线), L, R向左向右延伸的最大长度, 然后通过递推来得到. ----------------------- ...
- BZOJ 3039: 玉蟾宫【dp】
Description 有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地.这片土地被分成N*M个格子,每个格子里写着'R'或者' ...
- [Tyvj1939] 玉蟾宫(单调栈)
传送门 题目 Description 有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地.这片土地被分成N*M个格子,每个格子里写 ...
- 洛谷P4147 玉蟾宫 (单调栈)
要求我们去找一个最大矩形面积. 单调栈做法(和P1950 长方形那道题类似(一模一样)). 1 #include<bits/stdc++.h> 2 using namespace std; ...
- [luogu]P1169 [ZJOI2007]棋盘制作[DP][单调栈]
[luogu]P1169 [ZJOI]棋盘制作 ——!x^n+y^n=z^n 题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋 ...
- 【BZOJ 4709】柠檬 斜率优化dp+单调栈
题意 给$n$个贝壳,可以将贝壳分成若干段,每段选取一个贝壳$s_i$,这一段$s_i$的数目为$num$,可以得到$num^2\times s_i$个柠檬,求最多能得到几个柠檬 可以发现只有在一段中 ...
- bzoj 1233: [Usaco2009Open]干草堆tower【dp+单调栈】
参考:https://www.cnblogs.com/N-C-Derek/archive/2012/07/11/usaco_09_open_tower.html 虽然长得很像斜率优化,但是应该不算-- ...
随机推荐
- macbook air 安装win7双系统
转自: http://jingyan.baidu.com/article/6d704a13f99f1a28da51ca49.html 1)遇到“No bootable device-insert bo ...
- intellij idea 如何更改编辑器文本字体和大小
换上了intellij idea之后,第一件事就是想要改变下文字字体,因为在我这个27寸的2k分辨率的屏幕上,文字显然太小了. intellij idea字体设值分成两部分,一部分是UI部分字体字号设 ...
- cURL的几个经典实例
1.cURL请求的基本步骤: (1)初始化 (2)设置选项,包括URL (3)执行并获取HTML文档内容 (4)释放cURL句柄 <?php //1.初始化 $ch = curl_init(); ...
- 【动态规划】拦截导弹_dilworth定理_最长递增子序列
问题 K: [动态规划]拦截导弹 时间限制: 1 Sec 内存限制: 256 MB提交: 39 解决: 10[提交][状态][讨论版] 题目描述 张琪曼:“老师,修罗场是什么?” 墨老师:“修罗是 ...
- DisJSet:Find them, Catch them(POJ 1703)
抓住他们! 题目大意:两个黑社会帮派,互相打架,现在你很多条信息,要你确定两个人是否属于不同帮派 这题很有趣,题目不是直接给你两个人是否是一个帮派的,他给你的是不同帮派的,也就是给你很多个不同的要你找 ...
- 【python】时间性能分析
参考: http://blog.jobbole.com/47619/ http://chenpeng.info/html/1754 1.计算整个程序运行时间,直接用linux的time命令即可 tim ...
- fedora yum 使用代理的方法
配置yum: 编辑/etc/yum.conf添加下列一行: proxy=http://domain/user:passwd@<proxy ip>:80 <proxy ip>:代 ...
- solr6.0学习
solr6.0学习(一)环境搭建准备工作:目前最新版本6.0.下载solr 6.0:Solr6.0下载JDK8 下载jdk1.8:jdk1.8[solr6.0是基于jdk8开发的]tomcat8.0 ...
- mysql 数据库获取当前时间
mysql> select now(); +---------------------+ | now() | +---------------------+ | 2016-05-27 17:34 ...
- Maven使用笔记(六)使用Maven进行多模块拆分
模块拆分是Maven经常使用的功能,简单梳理一下如何使用Maven进行多模块拆分, 只做归纳总结,网上资料很多,不再一步一步实际创建和部署. >>建立Maven多模块项目 一个简单的Jav ...