問題描述
小 a 有乙個 n×m 的矩陣,矩陣中 1~n*m 這(n*m)個整數均出現過一次。 現在小 a 在這個矩陣內選擇乙個子矩陣,其權值等於這個子矩陣中的所有數的最 小值。小 a 想知道,如果他選擇的子矩陣的權值為 i(1<=i<=n×m),那麼他選擇 的子矩陣可能有多少種?小 a 希望知道所有可能的 i 值對應的結果,但是這些結 果太多了,他算不了,因此他向你求助。輸入格式
第一行,兩個整數 n,m。輸出格式接下來的 n 行,每行 m 個整數,表示矩陣中的元素。
n×m 行,每行乙個整數,其中第 i 行的整數表示如果小 a 選擇的子矩陣權 值為 i,他選擇的子矩陣的種類數。資料範圍
對於 30%的資料,1<=n,m<=50;首先說說o(對於全部的資料,1<=n,m<=300。
n2m2
) 的暴力做法:
考慮固定矩陣左上角,如何求出以該點為左上角的所有矩陣的權值?令f[
i][j
] 表示以當前左上角,(i
,j) 為右上角構成的矩形的權值,那麼有遞推關係:f[
i][j
]=mi
n(f[
i−1]
[j],
f[i]
[j−1
],ma
p[i]
[j])
對於乙個固定的左上角,求出所有矩陣的權值的時間複雜度為o(
nm) 。左上角一共討論o(
nm) 個,所以總時間複雜度o(
n2m2
) 。
正解:從權值的角度考慮。固定矩陣上下邊界後,如何求某一權值的矩形有多少個?那麼首先要找到當前權值的點在**。顯然,當遇到左邊第乙個權值小於它的矩形就停止,這樣就找到了它的左邊界。右邊界同理。這樣的話,以該上下邊界的矩陣個數為(r
ight
[k]−
k+1)
(k−l
eft[
k]+1
) 。
以某點為中心,找左右邊界的操作可以通過單調佇列(單調棧)用o(
m)解決。列舉上下邊界的時間複雜度是o(
n2) ,總時間複雜度o(
n2m)
。當然也可以是o(
nm2)
。
#include
#define min(x,y) ((xint n,m,min[305],ans[90005],map[305][305],q[305],tail,l[90005],r[90005];
int main()
q[++tail]=k;
}while(tail)r[q[tail]]=m,tail--;
for(k=m;k>=1;k--)
q[++tail]=k;
}while(tail)l[q[tail]]=1,tail--;
for(k=1;k<=m;k++)ans[min[k]]+=(r[k]-k+1)*(k+1-l[k]);}}
for(i=1;i<=n*m;i++)printf("%d\n",ans[i]);
}
NKOJ 3861 子矩陣(矩陣dp 單調佇列)
問題描述 小 a 有乙個 n m 的矩陣,矩陣中 1 n m 這 n m 個整數均出現過一次。現在小 a 在這個矩陣內選擇乙個子矩陣,其權值等於這個子矩陣中的所有數的最 小值。小 a 想知道,如果他選擇的子矩陣的權值為 i 1 i n m 那麼他選擇 的子矩陣可能有多少種?小 a 希望知道所有可能的...
bzoj1047(單調佇列,矩陣中)
沒那麼難,不需要什麼二維單調佇列,其實只要改變一下順序就好 為了思路清晰,這裡採用的結構體 結構體函式寫的單調佇列 剛開始感覺不會,看hzwer的blog,上面說,題解都太麻煩,還不如手推,就沒繼續看下去,事實證明這道題回來一看就秒了,也不知道是怎麼想的。猜的?其實就是一行乙個單調佇列,端點每往右移...
單調棧,單調佇列
大多數借鑑了 單調佇列是什麼呢?可以直接從問題開始來展開。poj 2823 給定乙個數列,從左至右輸出每個長度為m的數列段內的最小數和最大數。數列長度 n 106,m n 我們知道,解法 在暴力列舉的過程中,有乙個地方是重複比較了,就是在找當前的f i 的時候,i的前面其它m 1個數在算f i 1 ...