题意:从n个数中选出m段不相交的连续子段,求这个和最大。
分析:经典dp,dp[i][j][0]表示不取第i个数且前i个数分成j段达到的最优值,dp[i][j][1]表示取了第i个数且前i个数分成j段达到的最优值。
那么有:
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]).
dp[i][j][1]=max(dp[i-1][j-1][0]+a[i],max(dp[i-1][j-1][1],dp[i][j][1])+a[i])).
红色部分略坑,仔细体会一下,因为连续的一段可能拆成多一段刚好符合m段到达最好,不一定得选一段连续的子系列只当成一段最好,可能分成多段更优。
由于n过大,使用滚动数组优化空间。
#include <algorithm> #include <cstdio> #include <cstring> #define N 1000010 #define inf 0x3f3f3f3f using namespace std; int dp[2][N][2],a[N]; int n,m; int main() { while(scanf("%d%d",&m,&n)>0) { for(int i=1;i<=n;i++)scanf("%d",&a[i]); for (int i = 0; i <= m; i++) { dp[0][i][0] = dp[1][i][0] = dp[0][i][1] = dp[1][i][1] = -inf; } dp[0][0][0]=dp[0][0][1]=0; for(int i=1,t=1;i<=n;i++,t=!t) { for(int j=0;j<=i&&j<=m;j++) { dp[t][j][0]=max(dp[!t][j][0],dp[!t][j][1]); if(j)dp[t][j][1]=max(dp[!t][j-1][0]+a[i],max(dp[!t][j][1],dp[!t][j-1][1])+a[i]); } } printf("%d\n",max(dp[n&1][m][0],dp[n&1][m][1])); } }
时间: 2024-10-13 23:32:10