题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024
题意就是有n个数分成m段,求最大的和;
dp[i][j]表示把 j 个数分成 i 段,选择第 j 个数的结果,而并不是当前的最优解,
那么要考虑的是第i个数的数是自己成一段还是和前面的成一段
所以dp[i][j]=max(dp[i][j-1]+a[j], Max+a[j]); 其中Max为前 j-1 个数字分成 i-1 段中的最大值;
由于题中n为100w,m不知道是多少,所以开二维数组可能不行因为只有每个状态就只和它的前一个状态有关,所以我们可以用dp【2】【N】来实现滚动数组;
异或^是相同为0,不同为1,可以用^1来转换状态;
本题要考虑边界问题;
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <vector> #include <algorithm> using namespace std; #define N 1000050 #define MOD 1000000007 #define met(a, b) memset(a, b, sizeof(a)) #define INF 0x3f3f3f3f typedef long long LL; int n, m, dp[2][N], a[N]; int main() { while(scanf("%d %d", &m, &n)!=EOF) { met(dp, 0); met(a, 0); for(int i=1; i<=n; i++) scanf("%d", &a[i]); int Max, ans, k; k = 0; for(int i=1; i<=m; i++) { k = k^1; dp[k][i] = dp[k^1][i-1]+a[i];///选择第i个数,分成i段,所以只能自己成一段,那么只能这样写; Max = dp[k^1][i-1]; ans = dp[k][i]; for(int j=i+1; j<=n; j++)///j要从i+1开始是因为:要分成i段至少要有i个数,还有就是下面有个j-1; { Max = max(Max, dp[k^1][j-1]);///Max为前j-1个数分成i-1段中的最大值; dp[k][j] = max(Max + a[j], dp[k][j-1] + a[j]); ///自己成一段(Max);和前面的成一段(dp[i][j-1]); ans = max(dp[k][j], ans); } } printf("%d ", ans); } return 0; }