题目的要求是找一个点然后以这个点往左或者往右砍树,要求每砍的高度严格小于上一次砍的树的高度,求权值最大
贪心可以知道以极大值为初始点,往左或者往右砍是最佳的
设前一颗砍的高度为c
设左右边其中一个高度为a另一个为b
如果c>a>b的话因为那么肯定可以先把a砍了再去看后面的
如果a>c>b的话那a就不能砍了,最佳的肯定是把b给砍了
如果c>(a=b)的话我们不知道要砍左边还是右边才是最优的,那我们就可以分两种情况递归下去
当我们左右都砍不了时也就是递归到边界的时候我们就返回
同时在递归的时候保存他们的最大值
cpp
const int inf = 0x3f3f3f3f3f3f3f3f, N = 2e5 + 5, mod = 1e9 + 7;
int h[N], w[N];
int n;
int res = 0, maxx = 0;
void cal(int l, int r,int mid)
{
maxx = max(maxx, res);
if (h[l] >= h[mid] && h[r] >= h[mid]) return;
if (l<0 || r>n+1) return;
if (h[l] > h[r]&&h[mid]>h[l]) {
res += w[l];
cal(l - 1, r, l);
res -= w[l];
}
else if (h[l] > h[r] && h[mid] > h[r]) {
res += w[r];
cal(l, r + 1, r);
res -= w[r];
}
else if (h[l]<h[r] && h[mid]>h[r]) {
res += w[r];
cal(l, r + 1, r);
res -= w[r];
}
else if (h[l]<h[r] && h[mid]>h[l]) {
res += w[l];
cal(l - 1, r, l);
res -= w[l];
}
else if (h[l] == h[r]) {
res += w[l];
cal(l - 1, r, l);
res -= w[l];
res += w[r];
cal(l, r + 1, r);
res -= w[r];
}
}
signed main()
{
ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--)
{
maxx = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> h[i];
}
for (int i = 1; i <= n; i++) {
cin >> w[i];
maxx = max(maxx, w[i]);
}
h[n + 1] = -1; h[0] = -1;
w[n + 1] = 0;
for (int i = 1; i <= n; i++) {
if (h[i] >= h[i - 1] && h[i] >= h[i + 1]) {
if (h[i] == h[i - 1] && h[i] == h[i + 1]) continue;
res = w[i];
cal(i - 1, i + 1, i);
}
}
cout << maxx << "\n";
}
}