【BZOJ2228】[ZJOI2011]禮物(單調棧)
阿新 • • 發佈:2018-10-31
【BZOJ2228】[ZJOI2011]禮物(單調棧)
題面
題解
如果這個玩意不是一個三維立方體,而是一個二維的矩形,讓你在裡面找一個最大正方形,那麼全世界都會做。
丟到三維上?似乎區別也不是很大啦。
我們先把每一層一片一片的剖開考慮,預處理以某個位置為左上角的最大正方形邊長。這個很容易求,可以用單調佇列做到\(O(pqr)\)。接下來列舉某個左上角,把在每一層上的這個邊長全部扣下來,形成一個序列。那麼要求的就是最小值乘以選擇的長度的最大值。這個東西顯然還是可以單調佇列求。
那麼這樣子複雜度就變成了\(O(pqr)\),再分別按照另外兩維切片,就可以考慮出所有位置的答案了。
然而我想了半天怎麼求以某個點為左上角的最大正方形,就像蘿蔔求助,然後被蘿蔔狠狠狠狠狠的批判了一番:“不就搞個變數掃一遍就好了嗎?”,我“???”(智商掉線.jpg,最近智商已經沒了,要找點智商了。)
大概是這樣的:按照某一行來做,從左往右確定每一列的答案,暴力拓展最大的合法正方形,假設邊長為\(N\),那麼往右移一個位置的時候直接從\(N-1\)還是列舉就好了。我實在是太菜了,這都不會。
注意一下他這個字串的讀入順序並不是\(pqr\),而是\(qpr\)。
#include<iostream> #include<cstdio> using namespace std; #define MAX 155 inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } char g[MAX][MAX][MAX]; int s[MAX][MAX][MAX]; int n[MAX][MAX][MAX]; int p[MAX][MAX]; int L[MAX],R[MAX],Q[MAX],H,T; int a,b,c,ans; bool check(int b,int c,int x,int y,int N) { if(x+N-1>b||y+N-1>c)return false; int xx=x+N-1,yy=y+N-1; return p[xx][yy]-p[xx][y-1]-p[x-1][yy]+p[x-1][y-1]==N*N; } void Calc(int a,int b,int c) { for(int i=1;i<=a;++i) { for(int j=1;j<=b;++j) for(int k=1;k<=c;++k) p[j][k]=s[i][j][k]+p[j-1][k]+p[j][k-1]-p[j-1][k-1]; for(int j=1;j<=b;++j) { int N=0; for(int k=1;k<=c;++k) { while(check(b,c,j,k,N+1))++N; n[i][j][k]=N;N-=1; } } } for(int j=1;j<=b;++j) for(int k=1;k<=c;++k) { T=0; for(int i=1;i<=a;++i) { while(T&&n[Q[T]][j][k]>=n[i][j][k])--T; L[i]=Q[T]+1;Q[++T]=i; } T=0; for(int i=a;i>=1;--i) { while(T&&n[Q[T]][j][k]>=n[i][j][k])--T; R[i]=T?Q[T]-1:a;Q[++T]=i; } for(int i=1;i<=a;++i) ans=max(ans,n[i][j][k]*(R[i]-L[i]+1)); } } int main() { b=read();a=read();c=read(); for(int i=1;i<=a;++i) for(int j=1;j<=b;++j) scanf("%s",g[i][j]+1); for(int i=1;i<=a;++i) for(int j=1;j<=b;++j) for(int k=1;k<=c;++k) s[i][j][k]=(g[i][j][k]=='N'); Calc(a,b,c); for(int i=1;i<=b;++i) for(int j=1;j<=a;++j) for(int k=1;k<=c;++k) s[i][j][k]=(g[j][i][k]=='N'); Calc(b,a,c); for(int i=1;i<=c;++i) for(int j=1;j<=b;++j) for(int k=1;k<=a;++k) s[i][j][k]=(g[k][j][i]=='N'); Calc(c,b,a); printf("%d\n",4*ans); return 0; }