51nod 1052 最大M子段和 (區間dp)

2021-08-08 23:46:12 字數 1258 閱讀 2897

看到大佬題解,感覺很全面

動態規劃,借助矩陣可以直觀的看到計算過程。

定義二維陣列dp, dp[ i ][ j ],表示前 j 項所構成 i 子段的最大和,且必須包含著第j項,即以第j項結尾

然後是乙個遞推過程。

求dp[ i ][ j ],有兩種情況

1、dp[ i ][ j ] = dp[ i ] [ j-1 ] + a[ j ] ,即把第j項融合到第 j-1 項的子段中,子段數沒變

2、dp[ i ][ j ] = dp[ i-1 ] [ t ] + a[ j ],(i-1<= t < j )

把第 j 項作為單獨的乙個子段,然後找一下i-1個子段時,最大的和,然後加上a[ j ]

然後比較上面兩種情況,取大的。

下面看圖,紅色數字為輸入的序列:

可以看出dp[3][6]只和dp[3][5]和上一行中紅色圈中的有關,所以把上一行用pre這個一維陣列來表示,他們的最大值用乙個數表示,每次記得跟更新就行了。

我要說一下我自己對這個題的理解,首先看到題,我想到的是區間dp,區間dp需要三重迴圈就是n^3是不能解決問題的,我直接否定了它,正確的dp思路(我以為的)應該是先去想怎麼能在分成k組的時候用到k-1組的資料。所以dp陣列應該是二維的其中一維表示分成幾組,dp[i][j]表示分成i組,j應該表示什麼應該是以j為結尾。裡面必須有a[j]。那我們就會去想如果乙個沒有a【j】的數最大怎麼辦,我們可以用ans一直更新比ans大的數。dp[i][j]應該是誰遞推而來的呢,肯定是前一行位置j之前的最大值,和這一行前面的dp[i][j-1]。我們現在想前面的j之前的最大值,每一次都要更新j,這不還是n^3,事實上o(1)就可以得到

前一行位置j之前的最大值,這樣就出來了o(n^2)的演算法。

為什麼算原創的,因為,我只是用了那個dalao部分說明和

#includetypedef long long ll;

using namespace std;

int n,m;

ll a[5050];

ll dp[5002]=;

ll pre[5002]=;//記錄上一行

int main()

}cout<

51Nod 1052 最大M子段和

n個整數組成的序列a 1 a 2 a 3 a n 將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 13一段,6一段,和為26。刷刷水有益身心健康。不過我還是沒有一眼看出來。考慮...

51Nod1052 最大M子段和

n個整數組成的序列a 1 a 2 a 3 a n 將這n個數劃分為互不相交的m個子段,並且這m個子段的和是最大的。如果m n個數中正數的個數,那麼輸出所有正數的和。例如 2 11 4 13 5 6 2,分為2段,11 4 13一段,6一段,和為26。input 第1行 2個數n和m,中間用空格分隔。...

51Nod 1052 最大M子段和

先將同符號的每一段存下來,並記錄前後段標號,將正數段總和記錄為tot 開乙個最小堆存每一段的abs值。每次從堆中取出乙個x 去掉這一段,並將左右的段與之合併再存入堆中,作為撤銷或更改操作。每次操作都會減少一段,直到段數 k就退出。include include include include def...