题目链接:http://acm.tzc.edu.cn/acmhome/vProblemList.do?&method=problemdetail&id=4996
题目大意:给定一个数列a,记a[i..j]表示从i到j的子列,定义sum = min(k, i, j){a[k]} * sum[i..j],即子列a[i..j]中的最小值乘子列的和,求最大的sum。
分析:这题网上大多做为单调栈的例题,但是其实DP也可以(而且代码更简洁),两种代码我都给出来了。
重点在于求出以a[i]为最小值的最长子列,单调栈就不说了(网上太多了),说一下DP吧。以求左边最长子列为例,用dp[i]表示,看下面这一行代码
for (int j = i - 1; j > 0 && a[j] >= a[i]; dp[i] += dp[j], j -= dp[j]);
这就求出dp[i]了。因为当a[j] >= a[i]时,不小于a[j]的数都不小于a[i],但小于a[j]的数可能也不小于a[i],所以考察左边小于a[j]的第一个数即j - dp[j]。相比单调栈,这一行代码就显得很简洁了。时间上我用DP快一点,可能是因为我的stack实现直接用的STL,实际上两者是等价的,出栈的过程就相当于这里的j -= dp[j],单调栈中有一个new_node.pre += tmp.pre,这句话和dp[i] += dp[j]是一样的,tmp.pos和这里的j是一一对应的,只不过保存数据的结构不一样而已。
//单调栈
#include
#include
#include
#include
#include
#include