題目傳送門
好吧,好像是我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...