题目链接:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1631
题目大意:从长度为n的非负数列中选取m个数,使选取的数和最大,其中选取的每一个连续子序列的第一个数不计入求和(比如选取a1, a2, a3,那么和为a2 + a3。特别地,选取的任意单个数求和为0)。此外,数列首尾视为相连。
分析:如果没有首尾相连的条件,这题就是简单的dp。加上首尾相连之后,第一想法是环形dp,即在数列后面接上m - 1个数(超过m - 1个数的部分都可以归为原数列的情况)。但是这样会导致一个问题:原数列的前面部分可能被选取2次,即接在原数列后面的数和原数列中的数同时被选取。只要前面某个数足够大就会发生这样的情况。所以这种做法是不对的。
正确的做法是:先忽略首尾相连的条件求出一个最大值,那么什么情况下这个最大值不对呢?就是当a0和a(n-1)同时被选的情况。用dp[i][j][1]表示从前i个数选j个数且a[i]必选时的最大值,在普通情况下dp[0][1][1] = 0,但选了a(n-1)之后,dp[0][1][1] = a[0]。这就是仅有的区别。所以可以这样处理这种情况:令dp[0][1][1] = a[0]并且dp[n - 1][m][1]就是这种情况下的最大值。注意dp[n - 1][m][1]可能并非从dp[0][1][1]转化而来,需要把除dp[0][1][1]之外的其他值预先置为-inf,这样强迫后面的所有值从dp[0][1][1]转化而来。当然,把其他所有值预置为-inf是不必要的,只需要预置部分值就行了(就是动态规划的初值,如dp[0][0][0],在普通情况下这些值应该是0),但是这样无疑可以简化操作与代码,反正这也花不了多少时间。
#include
#include
#include
#include
#include
#include