Loading

gk的爬山之旅(单调栈 DP)

题目:

​ 有n座山峰,每个山峰都有自己的高度和值,现在出题人要在群山中穿梭。穿梭有两个条件:1 他们只会去高度大于当前所在山峰的高度的山峰;2 他们只能到达左右两边第一个比自己高的山峰。

思路:

​ 整理题意后明显可以发现是一个单调栈题目,对于每个i,预处理出左右第一个可达的山峰,就可以将题目转化成一个DAG上的最长路问题,可以通过记忆化搜索的方式解出。

实现:

​ 在实现的过程中,样例无法通过,原来是疏忽了一个条件。因为山峰的值数组是严格递增或者严格递减的,所以对于 8 8 8 8 6,我们应该从6跳到最左边的8,才能获得最大的收益。

#include <bits/stdc++.h>
    
using namespace std;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define all(x) x.begin(), x.end()
#define pb push_back
#define ios ios::sync_with_stdio(false);cin.tie(0);
#define debug(x)    cout << x << endl;
#define SZ(x)    (int)x.size()
typedef long long ll;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
void read(int &x) {int s = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) {f = (ch == '-' ? -1 : f); ch = getchar();} while(isdigit(ch)) {s = s * 10 + ch - '0'; ch = getchar();} x = s * f;}

const int N = 1000005;
int n;
ll f[N];
int h[N], g[N];
int l[N], r[N]; //左边第一个比h[i]大的,右边第一个比h[i]大的
vector<int> G[N];

void init()
{
    for(int i = 1; i <= n; i ++)
        f[i] = -1, G[i].clear(), l[i] = r[i] = -1;
}

void dfs(int u) //DAG上DP
{
    if(f[u] != -1)  return;
    f[u] = 0;
    for(int v : G[u])
    {
        if(f[v] == -1)  dfs(v);
        f[u] = max(f[u], f[v] + abs(g[u] - g[v]));
    }
}

void solve()
{
    scanf("%d", &n);
    init();
    for(int i = 1; i <= n; i ++)
        scanf("%d", &h[i]);
    for(int i = 1; i <= n; i ++)
        scanf("%d", &g[i]);

    stack<int> stk1, stk2;
    int idx;

    for(int i = 1; i <= n; i ++)
    {
        idx = i;
        while(stk1.size() && h[stk1.top()] <= h[i])
        {
            if(h[i] == h[stk1.top()])    idx = stk1.top();
            stk1.pop();
        }
        if(stk1.size())    l[i] = stk1.top();
        stk1.push(idx);
    }

    for(int i = n; i >= 1; i --)
    {
        idx = i;
        while(stk2.size() && h[stk2.top()] <= h[i])
        {
            if(h[i] == h[stk2.top()])    idx = stk2.top();
            stk2.pop();
        }
        if(stk2.size()) r[i] = stk2.top();
        stk2.push(idx);
    }

    for(int i = 1; i <= n; i ++)
    {
        if(l[i] != -1)  G[i].pb(l[i]);
        if(r[i] != -1)  G[i].pb(r[i]);
    }

    for(int i = 1; i <= n; i ++)
        dfs(i);

    for(int i = 1; i <= n; i ++)
        printf("%lld ", f[i]);
    puts("");
}

signed main()
{
    int _ = 1;
    scanf("%d", &_);
    while(_--)
        solve();
}
posted @ 2022-09-08 13:30  DM11  阅读(48)  评论(0编辑  收藏  举报