问题:
有一天,小猫\(rainbow\)和\(freda\)来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。
这片土地被分成\(N \times M\) 个格子,每个格子里写着\(’R’\)或者\(’F’\),\(R\)代表这块土地被赐予了\(rainbow\),\(F\)代表这块土地被赐予了\(freda\)。
现在\(freda\)要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着\(’F’\)并且面积最大。
它们决定,如果你找到的土地面积为\(S\),它们给你\(3 \times S\)两银子。
解:
这题有多种做法 双端队列的解法我就不说了
这里介绍单调栈和DP 的方法
1.单调栈
首先我们先注意到对于一个合法的序列 答案一定是长度 $\times min(H) $
并且对于一个单调的栈 从左到右每个元素都能够和右边的配成对 并且高度为当前元素的H
考虑当栈顶元素的H>枚举到的H
那么就不满足单调性 所以我们需要进行强制单调 好让成为一个单调的序列
最后考虑再次统计答案即可
code:
#include<bits/stdc++.h>
using namespace std;
int mapp[2000][2000];
int n,m;
int ans=0;
int sum[2000][2000];
struct node
{
int H,l;
};
stack<node> S;
void get()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int len=0;
while(S.size()&&S.top().H>sum[i][j])
{
len+=S.top().l;
ans=max(ans,len*S.top().H);
S.pop();
}
S.push(node{sum[i][j],len+1});
}
int len=0;
while(S.size())
{
len+=S.top().l;
ans=max(ans,len*S.top().H);
S.pop();
}
}
}
void ssum()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
sum[i][j]=(mapp[i][j]?sum[i-1][j]+1:0);
}
}
}
int main()
{
char c;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
{
c=getchar();
while(c!='F'&&c!='R')
{
c=getchar();
}
if(c=='F')
{
mapp[i][j]=1;
}
else
mapp[i][j]=0;
}
}
ssum();
get();
cout<<3*ans;
}
2 DP
对于每个点考虑
当前这个点向左所能延伸到到最远的距离就是 他上面和他的离得最近的距离
dp一下即可
来道经典题:
翻转矩阵
何老板给你一个H*W的网格棋盘,每个方格都被涂上了黑色或白色。
你可以进行任意次下列操作:
任选一行(或一列),将该行(列)的方格颜色翻转,即白色变黑,黑色变白。
何老板希望你能在棋盘上找出最大的一个黑色矩形。该矩形中的方格全是黑色,请你输出该矩形的面积。
注意到能够成为矩形到充要条件是每个2$\times$2 的小矩形异或值为0
所以我们考虑构建一个新的矩阵
找最大的面积