P4147 玉蟾宮
題目背景
有一天,小貓 rainbow 和 freda 來到了湘西張家界的天門山玉蟾宮,玉蟾宮宮主藍兔盛情地款待了它們
並賜予它們一片土地。
題目描述
這片土地被分成 \(N\times M\) 個格子,每個格子裡寫著 'R' 或者 'F',R 代表這塊土地被賜予了 rainbow,
F 代表這塊土地被賜予了 freda。現在 freda 要在這裡賣萌。。。它要找一塊矩形土地,
要求這片土地都標著 'F' 並且面積最大。但是 rainbow 和 freda 的 OI 水平都弱爆了,找不出這塊土地,
而藍兔也想看 freda 賣萌(她顯然是不會程式設計的……),所以它們決定,如果你找到的土地面積為 S,它們每人給你 S 兩銀子。
輸入格式
第一行兩個整數 N,M,表示矩形土地有 N 行 M 列。
接下來 N 行,每行 M 個用空格隔開的字元 'F' 或 'R',描述了矩形土地。
輸出格式
輸出一個整數,表示你能得到多少銀子,即 (3\times \text{最大 'F' 矩形土地面積}) 的值。
輸入輸出樣例
輸入 #1
5 6
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
輸出 #1
45
說明/提示
對於 50% 的資料,1 <= N,M <= 200
對於 100%100%100% 的資料,1≤N,M≤1000
我們可以想到O(n^4)的暴力。
列舉每個矩形的左上角和右下角,然後算出每個矩形的貢獻,
最後在對每個矩形的貢獻取個max便是最後的答案
但這樣只能過一半的資料,然後我們就要考慮優化。
我們可以對每個點求出他向下所能延伸的高度,也就是矩形的高。
那麼怎麼確定矩形的寬呢?
如果,我們能求出他所能向左和向右能延伸的長度,那麼這個矩形的貢獻不就很好的求出來了嗎?
一個點能向左右兩邊延伸,當且僅當左右兩邊能向下延伸的高度比他大的時候。
我甩給你一張圖:
顏色表示每個點能向下延伸的最大長度,看看這張圖應該能明白吧(霧)
自己可以手動模擬一下。
求序列中第一個比他小的數,那這不是單調棧嗎?
所以,我們對每一行從左往右跑一邊單調棧,在反過來跑一邊就可以求出每個點的貢獻
最後答案一定不要忘記乘三(當初我傻乎乎的調了半天才發現沒乘三)
程式碼
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
char ch;
int n,m,top,ans;
int sta[1010],ls[1010],rs[1010],h[1010][1010];
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
return s * w;
}
int main()
{
n = read(); m = read();
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
cin>>ch;
if(ch == 'F') h[i][j] = h[i-1][j] + 1;//求出每個點能向下延伸的高度也就是矩形的高
}
top = 0; sta[++top] = 0;
for(int j = 1; j <= m; j++)//正著跑一遍單調棧求出每個點能向左延伸的長度
{
while(top && h[i][sta[top]] >= h[i][j]) top--;
ls[j] = sta[top]; sta[++top] = j;
}
top = 0; sta[++top] = m+1;
for(int j = m; j >= 1; j--)//反著跑一遍單調棧求出每個點向右能延伸的長度
{
while(top && h[i][sta[top]] >= h[i][j]) top--;
rs[j] = sta[top]; sta[++top] = j;
}
for(int j = 1; j <= m; j++)
{
ans = max(ans,3 * h[i][j] * (rs[j]-ls[j]-1));//統計答案
}
}
printf("%d\n",ans);
return 0;
}
聽別的大佬用懸線法切了這道題。
但蒟蒻我太菜了,沒學會。
先佔上坑吧,後期再補。