题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1087
方法:设F(ni)为当第ni个作为一个递增非连续字段最后一个元素的时候,该字段累加的最大值,设第x个元素的值为v(x)。然后建立状态转移方程:
F(ni) = max({F(ai)+v(ni) | v(ai)<v(ni) and 0<=ai<ni}) ,对每一个这样的第ni个元素做这样的处理,最后的解为:
max( F(x) | 0<=x<=n).
代码实现的时候会有一个优化,那就是对于这样的情况:
1 2 3 4 5 9 8
考虑那个8的时候,是从9往前探寻所有小于8的数,然后用所有 以这些数作为字段结尾的字段和加上8来比较,取最大的作为以8作为字段末尾的字段最大和,找到5是往前找到的第一个小于8的数,得到一个8作为字段末尾的字段最大和的预估值,然后就不需要在去考虑5前面的那些1 2 3 4了,因为他们肯定比不过5.
所以对每一个数都要记录一个东西, 那就是其往直接前面走连续不断的一个递减序列长度l,这样把一个数考虑后,就不用直接去一个一个考虑前面的,而是直接往前跳l个位子,开始新的一个考虑。
比如数据:
x y z a b c d 1 2 3 4 5 9 8
考虑8作为字段末尾的字段最大和的时候,向前探寻到5的时候,取得一个最大和估值,然后不用再考虑5前面的那些1 2 3 4,而是直接跳到 d那个位置。
感谢:优化后速度还是没有起来,不知道为什么。
代码:

#include<iostream> #include<math.h> #include<algorithm> using namespace std; int const MAX =0x3f3f3f3f; int main() { int n; while(scanf("%d",&n) && n!=0 ) { int nums[1001]; int dp[1001]; int lessCount[1001]; memset(lessCount,0,sizeof(lessCount)); dp[0]=nums[0]=0; for(int i=1;i<=n;i++) scanf("%d",&nums[i]); for(int i=1;i<=n;i++) { if(nums[i]>nums[i-1]) lessCount[i] = lessCount[i-1]+1; else lessCount[i]=0; int max=-MAX; for(int j=i-1;j>=0;j--) { if(nums[i]>nums[j]) { max = max < nums[i]+dp[j] ? nums[i]+dp[j] :max; j-=lessCount[j]; } } dp[i]=max; } int max=-MAX; for(int i=0;i<=n;i++) max = max < dp[i] ? dp[i] :max; cout<<max<<endl; } return 0; }