51nod 1052 最大M子段和

2021-08-19 14:04:14 字數 1536 閱讀 8911

1052 最大m子段和

基準時間限制:2 秒 空間限制:131072 kb 分值: 80 

難度:5級演算法題

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,中間用空格分隔。n為整數的個數,m為劃分為多少段。(2 <= n , m <= 5000)

第2 - n+1行:n個整數 (-10^9 <= a[i] <= 10^9)

output

輸出這個最大和
input示例

7 2

-211

-413-56

-2

output示例

26
題解:設dp[i][j]表示前i元素擷取j段的最大值,要到達dp[i][j],有兩種策略:第一種是新建立一段,即從dp[x][j - 1]到達dp[i][j](x < i),第二種是在第j段後加入a[i],即從dp[i - 1][j]到達dp[i][j],此種寫法複雜度為o(n^3);

我們注意到,對於dp[x][j - 1],我們只需要其中最大值即可,故我們開乙個maxpre陣列,記錄(x < i)的j段最大值,成功的將複雜度降到o(n ^ 2);上述轉移方程為:dp[i][j] = max(maxpre[j - 1], dp[i - 1][j]) + a[i];

maxpre[j] = max(maxpre[j], dp[now][j]);

上述寫法仍然存在問題,空間爆了;很容易發現,dp陣列每次只需要用到兩維,故我們只需要開dp[2]即可,記錄乙個now代表當前使用哪一維,執行完一次for迴圈後now取反操作!

ac**

#include #include #include #include #include #include #include #include #include typedef long long ll;

using namespace std;

const ll maxn = 5555;

ll dp[2][maxn], a[maxn], maxpre[maxn];

int main()

} n = num;

memset(dp, 0, sizeof(dp));

memset(maxpre, 0, sizeof(maxpre));

ll now = 0, ans = 0;

for(ll i = 0; i < n; i++)

ans = max(ans, dp[now][m]);

now = !now;

} printf("%lld\n", ans);

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