1. 程式人生 > >[tyvj]P1939玉蟾宮[單調棧]

[tyvj]P1939玉蟾宮[單調棧]

但是 枚舉 har 張家界 inline cstring namespace 刪除 處理

[tyvj]P1939

玉蟾宮

——!x^n+y^n=z^n

背景

有一天,小貓rainbow和freda來到了湘西張家界的天門山玉蟾宮,玉蟾宮宮主藍兔盛情地款待了它們,並賜予它們一片土地。

描述

這片土地被分成N*M個格子,每個格子裏寫著‘R‘或者‘F‘,R代表這塊土地被賜予了rainbow,F代表這塊土地被賜予了freda。
現在freda要在這裏賣萌。。。它要找一塊矩形土地,要求這片土地都標著‘F‘並且面積最大。
但是rainbow和freda的OI水平都弱爆了,找不出這塊土地,而藍兔也想看freda賣萌(她顯然是不會編程的……),所以它們決定,如果你找到的土地面積為S,它們每人給你S兩銀子。

輸入格式

第一行兩個整數N,M,表示矩形土地有N行M列。
接下來N行,每行M個用空格隔開的字符‘F‘或‘R‘,描述了矩形土地。

輸出格式

輸出一個整數,表示你能得到多少銀子,即(3*最大‘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

輸出

45


考慮下面這種情況,就是所有寬為1的矩形的底在同一直線上,我們可以考慮用棧來維護,為什麽呢?

技術分享

註意到對於每一個小矩形,他對答案的貢獻為向左延伸和向右延伸的最大值,如果後面加進一個低一點的元素,那這個就沒啥用了,何不如直接刪掉?

用單調棧,一個記錄棧頂元素,另一個記錄在當前索引應刪除的元素。

那只需預處理出s[i][j]第i行,第j列,能向右延長的最大值,每次枚舉底部,那我們只需要每次加入元素並更新答案即可。

代碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 inline int read();
 6 int Max(int x,int y){return x>y?x:y;}
 7 namespace lys{
 8
const int N = 1e3 + 7 ; 9 int s[N][N],s1[N],s2[N],a[N][N]; 10 int n,m,ans,top,del; 11 void work(int row){ 12 top=0; 13 for(int i=1;i<=n+1;i++){ 14 del=i; 15 while(top&&s1[top]>=s[i][row]){ 16 ans=Max(ans,s1[top]*(i-s2[top])); 17 del=s2[top--]; 18 } 19 s1[++top]=s[i][row];s2[top]=del; 20 } 21 } 22 int main(){ 23 int i,j; 24 char c; 25 n=read(); m=read(); 26 for(i=1;i<=n;i++) 27 for(j=1;j<=m;j++){ 28 c=getchar(); 29 while(c!=F&&c!=R) c=getchar(); 30 if(c==F) a[i][j]=1; 31 } 32 for(i=1;i<=n;i++) 33 for(j=m;j>=1;j--) 34 s[i][j]=a[i][j]?s[i][j+1]+1:0; 35 for(i=1;i<=m;i++) work(i); 36 printf("%d\n",3*ans); 37 return 0; 38 } 39 } 40 int main(){ 41 lys::main(); 42 return 0; 43 } 44 inline int read(){ 45 int kk=0,ff=1; 46 char c=getchar(); 47 while(c<0||c>9){ 48 if(c==-) ff=-1; 49 c=getchar(); 50 } 51 while(c>=0&&c<=9) kk=kk*10+c-0,c=getchar(); 52 return kk*ff; 53 }

[tyvj]P1939玉蟾宮[單調棧]