BZOJ1084 SCOI2005 最大子矩陣

2022-03-29 17:11:33 字數 2649 閱讀 3839

bzoj1084: [scoi2005]最大子矩陣

這裡有乙個n*m的矩陣,請你選出其中k個子矩陣,使得這個k個子矩陣分值之和最大。注意:選出的k個子矩陣不能相互重疊。

第一行為n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下來n行描述矩陣每行中的每個元素的分值(每個元素的分值的絕對值不超過32767)。

只有一行為k個子矩陣分值之和最大為多少。

3 2 2

1 -3

2 3-2 3

9最大子矩陣嘛。。。

當然$dp$。。。

然後看見$m\in[1,2]$,果斷分類討論:

普通的最大連續欄位和,只不過是$k$個:

設$dp[i][j][0/1]$表示前$i$個數中取出$j$個矩形的最大和。

$0/1$表示第$i$gre數字不選或選。

轉移方程:

$$dp[i][j][0]=\max\left\{}dp[i-1][j][1]\\dp[i-1][j][0]\end\right.$$

$$dp[i][j][1]=\max\left\{}dp[i-1][j][1]\\dp[i-1][j-1][0]\end\right.$$

最後答案就是$\max\$。

我們考慮每一行能有什麼狀態:

$0$:空出這一行。

$1$:選擇左邊空出右邊.

$2$:選擇右邊空出左邊。

$3$:選擇這一行兩個,並且不作為乙個矩陣,而是左邊一列單獨乙個矩陣,右邊單獨乙個矩陣。

$4$:選擇這一行兩個,並且兩個一塊作為乙個矩陣的一部分。

定義$dp[i][j][k]$為當前處理到第$i$行,已經選了$j$個矩陣,當前行狀態為$k$的最大值,$k\in[0,4]$。

$$dp[i][j][0]=\max\left\{}dp[i-1][j][0]\\dp[i-1][j][1]\\dp[i-1][j][2]\\dp[i-1][j][3]\\dp[i-1][j][4]\end\right.$$

2. 如果選擇左邊空出右邊:

如果上一行的左邊沒有單獨地選擇成為矩陣,即選擇$1$或$3$,則$j$需要包含新選擇成為的矩陣。

即這一行的左邊的這個矩陣。

如果上一行為同時選擇兩列的為乙個矩陣的狀態,則只選擇單獨的左邊是不能包含進去上一行的矩陣的,所以也應$j-1$。

設這一行左邊的值為$v_1$,則有轉移方程:

$$dp[i][j][1]=\max\left\{}dp[i-1][j-1][0]\\dp[i-1][j][1]\\dp[i-1][j-1][2]\\dp[i-1][j][3]\\dp[i-1][j-1][4]\end\right\}+v_1$$

3. 右邊同理:

設這一行右邊的值為$v_2$,則有轉移方程:

$$dp[i][j][2]=\max\left\{}dp[i-1][j-1][0]\\dp[i-1][j-1][1]\\dp[i-1][j][2]\\dp[i-1][j][3]\\dp[i-1][j-1][4]\end\right\}+v_2$$

4. 選擇兩個分別單獨作為矩陣,類似只選擇左邊或右邊,不過是單獨選左邊和右邊合併了下:

$$dp[i][j][3]=\max\left\{}dp[i-1][j-1][1]\\dp[i-1][j-1][2]\\dp[i-1][j][3]\\dp[i-1][j-2][4]\quad j\geq 2\end\right\}+v_1+v_2$$

$$dp[i][j][4]=\max\left\{}dp[i-1][j-1][0]\\dp[i-1][j-1][1]\\dp[i-1][j-1][2]\\dp[i-1][j-1][3]\\dp[i-1][j][4]\end\right\}+v_1+v_2$$

好了,這個題就這麼做完了。

真是噁心啊。。。

然後這個題如果資料範圍再大一點,涉及到卡常的話,有個小優化:

當我們的程式要多次呼叫$dp[i][j][k]$並且只有$k$在瘋狂變化時,我們可以預先把$dp[i][j]$當成指標存入*$p$中。

這樣我們就不用每次都計算三維的$dp[i][j][k]$,而是直接呼叫$p[k]$。

這個優化可以瘋狂卡常。。。

因為$c++$中查詢乙個多維的陣列,要先進行複雜的乘法計算,然後再取位址,呼叫值。

這個優化直接把這個每次計算省掉了。

不過對於這個題好像沒有什麼用。。。

附**:

#include#include#include#include#define maxn 110

using namespace std;

int n,m,q,ans;

int val[maxn][3],dp[maxn][12][5];

inline int read()

while(c>='0'&&c<='9')

return date*w;

}void solve_one()

ans=max(dp[n][q][0],dp[n][q][1]);

printf("%d\n",ans);

}void solve_two()

ans=max(dp[n][q][0],max(max(dp[n][q][1],dp[n][q][2]),max(dp[n][q][3],dp[n][q][4])));

printf("%d\n",ans);

}void work()

void init()

int main()

bzoj1084 SCOI2005 最大子矩陣

description 這裡有乙個n m的矩陣,請你選出其中k個子矩陣,使得這個k個子矩陣分值之和最大。注意 選出的k個子矩陣 不能相互重疊。input 第一行為n,m,k 1 n 100,1 m 2,1 k 10 接下來n行描述矩陣每行中的每個元素的分值 每個元素的 分值的絕對值不超過32767 ...

BZOJ1084 SCOI2005 最大子矩陣

portal 注意到m只能為1或2 分類討論。m 1的時候其實就是最大k段連續子段和。f i j ma x f i j ma x f k j f k j 1 sum i s um k m 2時 g i j k 表示第一列到i,第二列到j,選了k個子矩陣的最大和 那麼有一下幾種情況 都不選 g i j...

BZOJ1084 SCOI2005 最大子矩陣

這題顯然是dp。定義f i j k 表示前i行j列裡有k個矩陣的最大元素總和。因為m 2,所以可以分兩種情況分別寫乙個dp,套一套容斥就行了。如下 include include include using namespace std const int maxn 105,maxk 15 int n...