感覺列舉的問題想要優化就一定要一邊列舉一邊維護些東西,或者要預處理之類的。
記得以前做了一道題
唯一的不同是求周長最長。做的時候參考了這道題,也是列舉右下角,然後用單調棧維護左上角。在那題中隨著j的增大,並不會影響單調棧內元素的單調性。然而在這題裡,隨著j的增大,越後面的元素增長得越快,因此後面的小的元素是有可能超過前面大的元素的。在這題中已經不能說是單調棧了,更像是乙個雙重有序的線性表。每次找最大值得遍歷一遍。時間複雜度o(mnk)。k是棧內元素的平均數量。跑起來速度還可以。
大白書上的方法更優,只用o(mn)。思路都大同小異,就是列舉格仔,維護一些資訊,然後o(1)計算出答案。我要o(k)才行。大致區別就是不一定要維護左上角,因為左上角的單調性已經無法保證了,所以不能避免再次列舉。應該換一下思路。之所以無法保證o(1)計算,那主要是因為維護的資訊量不夠。要加多一點。或許再維護下右上角= =?但兩邊的高度需要統一,那麼以誰為標準呢?該取哪那個左上角或右上角呢?資訊量似乎還是不夠,還是需要列舉。那就再加乙個資訊吧,我們需要統一高度,那不妨取當前格的最大高度好了。然後盡量的往兩邊延伸。維護好這個就能o(1)算出了。
如何維護是個大問題,高度很好維護,加一就好了。其實左右也很好維護的。如果上一層能延伸到這麼遠,那阻礙這一層的唯一因素就是這一層的格仔了。遍歷一下就能計算出來了。特別的為了方便維護,如果遇到石頭,那就要初始化,即left[i]=0,right[i]=n,up[i]=0。以便下一層的維護。
這個方法只會快一點。估計是棧內元素很少。
查出了一些邏輯上的錯誤,但僥倖的不影響結果。
雙重有序
#include#define maxn 1010
using namespace std;
int m,n;
char map[maxn][maxn];
int max[maxn][maxn];
inline void get(char& a)
while(a!='f'&&a!='r');
}struct node
node[maxn];
int top;
void add(int c,int h)
}int main()
u=d;}}
int ans=0;
for(int i=1;i<=m;i++)
add(j,i-max[i][j]+1);
for(int i=0;i維護高度,左右延伸
#include#define maxn 1010
using namespace std;
int m,n;
char map[maxn][maxn];
int up[maxn],lft[maxn],rit[maxn];
void get(char& a)
while(a!='f'&&a!='r');
}int main()
int ans=0;
for(int i=1;i<=m;i++)
else
lo=0;
for(int j=1;j<=n;j++)
else
if(map[i][j]=='f')}}
printf("%d\n",ans*3);
}return 0;
}
LA3029最大子矩陣
題意 給你乙個n m的矩陣 每個格仔不是 f 就是 r 讓你找乙個最大的 f 矩陣,輸出他的面積 3。思路 比較經典的題目了,現在想起來比較好想,以前的話想著很費勁,最早先用瓶頸法在杭電上過了乙個資料範圍比較小的,今天的這個目測瓶頸法過不去,瓶頸法的時間複雜度是o n 3 的,今天的這個我們可以用另...
LA3029 矩陣中求子矩陣最大問題
la3029 題意給你乙個矩陣,每個單元格要麼為空,要麼為滿,求全是空的最大子矩陣的格仔數 3.最樸素的演算法是列舉所有的子矩陣的左上角的點和右下角的點,這樣就能確定乙個矩形,然後再遍歷這個矩陣,看矩陣是否全是空。複雜度大概是o m 2 n 2 通過掃瞄法,每次維護left i j right i ...
最大子矩陣
描述 已知矩陣的大小定義為矩陣中所有元素的和。給定乙個矩陣,你的任務是找到最大的非空 大小至少是1 1 子矩陣。比如,如下4 4的矩陣 0 2 7 0 9 2 6 2 4 1 4 1 1 8 0 2 的最大子矩陣是 9 2 4 1 1 8 這個子矩陣的大小是15。輸入輸入是乙個n n的矩陣。輸入的第...