BZOJ 3039 玉蟾宮(DP 單調棧)

2021-09-06 17:21:07 字數 3225 閱讀 4467

每次看到我的提交都有點淡淡的憂傷t_t。。

看到此題我想到用字首和維護點ij向左和向上能拓展的最大長度,然後設狀態f(i, j, 0)表示ij這個點為最大矩形的右下角時的長(橫的),f(i, j, 1)表示ij這個店為最大矩形右下角時的寬(豎的),然後決策就是取點(i-1, j-1)的f值拓展一層為ij的,找到乙個可行最大解。

過了幾個樣例我以為就能過了0.0沒有認真考慮,,所以造成了前面2個wa。。原因很簡單,此方程不滿足最優子結構,因為你在拓展最大矩形的時候,不能保證(i+1, j+1)用到自己使得矩形增大,比如

0 0 0 1 1 0

1 1 1 1 1 0

0 0 0 1 1 0

當到點3,5的時候(下標從1開始),用到的是2,4,而2,4的最優解是向左拓展到2,1,因此方程轉移後得到的是乙個面積為4的矩形,與最優面積為6的矩形相悖,所以這樣設是錯誤的。

看了題解。。。嗯。。我這個方法其實是能用的,只不過換了一點和換了方程。

我們設l[x][y]表示xy這個點向左能拓展到的最遠的下標再-1,r[x][y]表示xy這個點想右能拓展到的最遠的位置再+1,根據矩形面積低×高,我們只需要將高算出來,找到乙個恰當的底,那麼面積就求出來了。

首先我們還得維護2個陣列,l[x][y]表示xy所構成的最大矩形的底的最左邊的點的位置,r[x][y]表示底最右邊的點的位置。接下來就是轉移了~

l和r很好求,現在我們要求的是l和r,xy的最大面積=(r[x][y]-l[x][y]+1)×高,高可以通過轉移時一步步獲得,r[x][y]=min(r[x][y]-1, r[x-1][y]),l[x][y]=max(l[x][y]+1, l[x-1][y]),這裡取max和min應該很好理解,嗯~此步驟就能看出我之前做法的不足了~這樣做是同方向的,所以底是最優的,而高顯然是最優的,所以矩形面積顯然是最優的。

#include #include #include #include #include #include using namespace std;

#define for1(i,a,n) for(i=a;i<=n;++i)

#define for2(i,a,n) for(i=a;i=n;--i)

#define for4(i,a,n) for(i=a;i>n;--i)

#define cc(i,a) memset(i,a,sizeof(i))

#define max(a,b) ((a)>(b)?(a):(b))

#define min(a,b) ((a)

#define read(a) scanf("%d", &a)

#define print(a) printf("%d", a)

inline int getnum()

const int n=1005;

int imap[n][n], l[n][n], r[n][n], l[n][n], r[n][n], h[n][n];

int main()

for1(i, 1, n)

for1(j, 0, m+1) r[0][j]=m+1;

for1(i, 1, n) for1(j, 1, m)

if(imap[i][j])

print(ans*3);

return 0;

}

然後是單調棧的做法,假設只有i為底的乙個點的高比i+!為底的乙個點的高,那麼i所在的底只有長度為1,而i+1所在底的長度為2,滿足單調性,即高度越高,比他矮的都能夠len+1,所以可以用單調棧實現。

(看了hzwer神犇的題解後才懂的)

我們維護a[i][j]表示ij點向上拓展的最長長度,那麼在i這一條底上,我們將所有的高進行單調棧處理,然後更新ans即可。(圖都不用存了)

#include #include #include #include #include #include using namespace std;

#define for1(i,a,n) for(i=a;i<=n;++i)

#define for2(i,a,n) for(i=a;i=n;--i)

#define for4(i,a,n) for(i=a;i>n;--i)

#define cc(i,a) memset(i,a,sizeof(i))

#define max(a,b) ((a)>(b)?(a):(b))

#define min(a,b) ((a)

#define read(a) scanf("%d", &a)

#define print(a) printf("%d", a)

inline int getnum()

const int n=1005;

int n, m, sum[n][n], s[n], l[n], ans, top;

void update(int h)

s[++top]=h[i]; l[top]=len+1;

} }len=0;

while(top)

}int main()

for1(i, 1, n) update(sum[i]);

print(ans*3);

return 0;

}

有一天,小貓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'矩形土地面積)的值。

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對於50%的資料,1<=n,m<=200

對於100%的資料,1<=n,m<=1000

poetize4

bzoj3039 玉蟾宮 單調棧

題目描述 給定乙個01矩陣,找出乙個面積最大的子矩陣,使得其中的元素均為1。輸出這個最大面積乘3。輸入第一行兩個整數n,m,表示矩形土地有n行m列。接下來n行,每行m個用空格隔開的字元 f 或 r 描述了矩形土地。輸出輸出乙個整數,表示你能得到多少銀子,即 3 最大 f 矩形土地面積 的值。樣例輸入...

BZOJ3039 玉蟾宮(懸線dp 單調棧)

description 有一天,小貓rainbow和freda來到了湘西張家界的天門山玉蟾宮,玉蟾宮宮主藍兔盛情地款待了它們,並賜予它們一片土地。這片土地被分成n m個格仔,每個格仔裡寫著 r 或者 f r代表這塊土地被賜予了rainbow,f代表這塊土地被賜予了freda。現在freda要在這裡賣...

刷題總結 玉蟾宮(bzoj3039單調棧)

有一天,小貓rainbow和freda來到了湘西張家界的天門山玉蟾宮,玉蟾宮宮主藍兔盛情地款待了它們,並賜予它們一片土地。這片土地被分成n m個格仔,每個格仔裡寫著 r 或者 f r代表這塊土地被賜予了rainbow,f代表這塊土地被賜予了freda。現在freda要在這裡賣萌。它要找一塊矩形土地,...