CodeForces - 1312E - Array Shrinking【dp+栈】

题意

  • 相邻的两个相等的数x可以合并为x+1,问可以通过合并操作得到的数列最小长度?

思路

  • 我们用 d p [ r ] dp[r] 表示数列 [ 1 , r ] [1, r] 的最小长度。显然如果数列 [ l , r ] [l, r] 的元素可以合并为一个数,也就是数列 [ l , r ] [l,r] 的长度为 1 1 ,那么我们可以得到 d p dp 方程: d p [ r ] = m i n ( d p [ r ] , d p [ l 1 ] + 1 ) dp[r]=min(dp[r], dp[l-1] + 1)

问题是我们如何来求某个数列区间是不是长度为 1 1 呢?

  • 我们可以用栈来实现. 令变量now为即将入栈的元素,如果栈顶元素和now相等,那么说明两者可以合并为now = now+1. 一直合并,直到now不能再和栈内元素合并为止.
  • 对于区间 [ l , r ] [l, r] ,如果最后栈的长度为 1 1 ,那么说明数列区间 [ l , r ] [l,r] 可以合并为一个数,也就是长度为 1 1 . 这个时候就可以更新 d p [ r ] dp[r] 啦~
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
inline int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

const int maxN = 505;

int n, a[maxN];
int dp[maxN];

int main()
{
    n = read();
    for(int i = 1; i <= n; ++ i )
        a[i] = read();
    dp[0] = 0;
    for(int r = 1; r <= n; ++ r )
    {
        dp[r] = dp[r - 1] + 1;
        stack<int>s;
        s.push(a[r]);
        for(int l = r - 1; l >= 1; -- l )
        {
            int now = a[l];
            while(true)
            {
                if(s.empty())
                {
                    s.push(now);
                    break;
                }
                if(now == s.top())
                {
                    s.pop();
                    ++now;
                } else { s.push(now); break; }
            }
            if(s.size() == 1)
                dp[r] = min(dp[r], dp[l - 1] + 1);
        }
    }
    cout << dp[n] << endl;
    return 0;
}
发布了273 篇原创文章 · 获赞 76 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104771773