51nod 1052 最大M子段和 DP

2021-08-09 10:49:38 字數 1431 閱讀 3269

題目傳送門

好吧,好像是我zz了,原來連續的一段數可以當做許多段數來看的……

(突然掀桌,氣得我都變成簡筆畫了!害得我wa了6發!)

其實這題就是一道非常水的dp題,定義f[

i][j

][0/

1]表示前

i 個數選了

j段,第三維表示當前的數是否被選在第

j 段數內。然後直接進行狀態轉移就行了。

突然發現這樣開陣列會ml

e,又發現好像第

i 個數的狀態只和第i−

1個數的狀態有關,那麼我們直接用滾動陣列來優化記憶體就行了。

附上ac**:

#include 

#include

#include

using

namespace

std;

const

int n=5010;

long

long n,m,a[n],f[2][n][2],sum,cnt;

int main(void)

f[0][0][0]=0;

for (int i=1; i<=n; ++i)

}return

printf("%lld\n",max(f[n&1][m][0],f[n&1][m][1])),0;

}

以上是本蒟蒻的辣雞dp,看了其他大佬的部落格後發現自己的想法就像乙個zz……

設外層迴圈

m 次,第

k次迴圈表示把整個序列分成

k 個子段所能得到的最大子段和。定義p

re陣列表示把整個序列分成k−

1 個子段所能得到的最大子段和。

顯然動規陣列f[

i]有兩種轉移方式:前i

−1個數分成了

k 個子段,把當前的數加到第

k個子段的末尾。前i

−1個數分成了k−

1 個子段,把當前的數作為第

k 個子段的開頭。

這樣的dp顯然比我的想法巧妙了許多,省了許多記憶體,**量也小了許多。

要盡快改進自己的思維方式,不要變成乙個資料結構學傻掉的人。

附上ac**:

#include 

#include

#include

using

namespace

std;

typedef

long

long ll;

const

int n=5010;

int n,m,a[n];

ll pre[n],f[n];

int main(void)

pre[n]=ans;

}return

printf("%d\n",pre[n]),0;

}

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...