题目来源:http://news.cnblogs.com/n/192014/
用a[i]表示第i个墙的高度,墙的个数记为n
思考:
1)两个墙x,y之间可以盛水的条件是a[x],a[y]是a[x...y]中的前两大数;
2)如果a[1...x-1]中存在a[i]>a[x],那么用k来替代x并不会使a[x...y]中盛水减少,同样如果a[y+1...n]中存在a[j]>a[y],可以用j替代y不会使a[x...y]中的盛水减少;
3) 如果得到了a[1...n]中的前两大i,j,那么它们一定是整个区间盛水的最优边界,a[i...j]中的水位就是min{a[i],a[j]},只需要考虑两边:a[1...i]和a[j...n];对于左边,如果a[1...i-1]中最大值为a[k],那么进一步a[k...i]区间的盛水情况也确定了,只需要考虑a[1...k]了,右边也是如此。
4)设a[t]是a[1...n]中最大值,那么a[1...t]中的盛水情况可以通过维护左连续区间最大值确定,同样右区间a[t...n]也可以确定:首先找到最大值,然后分别从左右两边遍历。
5)一次遍历的做法很巧妙:维护两端区间的最大值,这样可以确定一端的水位了。
int cal(void) { int ret = 0; int lmax = -1, rmax = -1; for (int i = 0, j = n-1; i <= j; ) { if (lmax < rmax) { if (a[i] > lmax) lmax = a[i]; else ret += lmax-a[i]; ++i; } else { if (a[j] > rmax) rmax = a[j]; else ret += rmax-a[j]; --j; } } return ret; }