题意
- 相邻的两个相等的数x可以合并为x+1,问可以通过合并操作得到的数列最小长度?
思路
- 我们用 d p [ r ] dp[r] dp[r]表示数列 [ 1 , r ] [1, r] [1,r]的最小长度。显然如果数列 [ l , r ] [l, r] [l,r]的元素可以合并为一个数,也就是数列 [ l , r ] [l,r] [l,r] 的长度为 1 1 1,那么我们可以得到 d p dp dp方程: d p [ r ] = m i n ( d p [ r ] , d p [ l − 1 ] + 1 ) dp[r]=min(dp[r], dp[l-1] + 1) dp[r]=min(dp[r],dp[l−1]+1)
问题是我们如何来求某个数列区间是不是长度为 1 1 1呢?
- 我们可以用栈来实现. 令变量now为即将入栈的元素,如果栈顶元素和now相等,那么说明两者可以合并为now = now+1. 一直合并,直到now不能再和栈内元素合并为止.
- 对于区间 [ l , r ] [l, r] [l,r],如果最后栈的长度为 1 1 1,那么说明数列区间 [ l , r ] [l,r] [l,r]可以合并为一个数,也就是长度为 1 1 1. 这个时候就可以更新 d p [ r ] dp[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;
}