1. 程式人生 > 實用技巧 >P4147 玉蟾宮

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;
}

聽別的大佬用懸線法切了這道題。

但蒟蒻我太菜了,沒學會。

先佔上坑吧,後期再補。

ENDING