【HDU 1024】 Max Sum Plus Plus
轉自:http://blog.acmol.com/%E3%80%90hdu-1024%E3%80%91-max-sum-plus-plus.acmol
博主寫的太好了,在下不敢造次模仿,就轉載過來,大家學習,進步。
題意:最大子串和的強化版,求給定序列的n段最大子串和。
思路:以前寫過一次,邊界條件一直沒處理好,這次處理也想了好一會兒。。我的DP實在是弱爆了。
先不考慮空間,寫出原始的狀態與狀態轉移方程:
f[i][j]表示只考慮前i個元素,包含第i個元素的j個最大子串的和。
g[i][j]表示只考慮前i個元素,未必包含第i個元素的j個最大子串的和。
則首先,由於第i個數可以與前面相鄰一段合成一段,也可以從它開始一段,得到第一個狀態轉移方程式:
f[i][j]=max{f[i-1][j],g[i-1][j-1]}+a[i]
由於g[i][j]分包含第i個元素與不包含第i個元素兩種情況,所以得第二個狀態轉移方程式:
g[i][j]=max{f[i][j],g[i-1][j]}
根據這兩個方程式就可以解決這個問題了。不過需要注意的是如果直接用二維數組,空間佔用會太大,可以使用空間壓縮。
代碼如下:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define CLR(arr,val) memset(arr,val,sizeof(arr))const int M=1000010;int a[M];long long f[M],g[M];int main(){ int n,m; while(~scanf("%d%d",&n,&m)) { for(int i=0;i!=m;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) g[i]=f[i]=-100000000000000LL; for(int i=0;i!=m;i++) { for(int j=n;j>=1;j--) { f[j]=max(f[j],g[j-1])+a[i]; g[j]=max(f[j],g[j]); } } printf("%I64d\n",g[n]); }}