# Codeforces 1312E. Array Shrinking (interval DP stack)

Posted by Nexy on Tue, 19 Oct 2021 23:28:07 +0200

## Meaning:

Give a length of n n The sequence of n for the same two adjacent numbers x x x can be replaced by a number x + 1 x+1 x+1, what is the shortest length of the sequence.
n < = 500 n<=500 n<=500

## Idea:

It's not hard to think of the data range as an interval dp
d p [ l ] [ r ] dp[l][r] dp[l][r] indicates interval [ l , r ] [l,r] [l,r] the shortest sequence length that can be combined.
that d p [ l ] [ r ] = m i n ( d p [ l ] [ k ] + d p [ k + 1 ] [ r ] ) dp[l][r]=min(dp[l][k]+dp[k+1][r]) dp[l][r]=min(dp[l][k]+dp[k+1][r])
when [ l , k ] [l,k] [l,k] and [ k + 1 , r ] [k+1,r] [k+1,r] can also be merged? When the shortest length of two intervals is 1 1 1 and the remaining numbers are the same.
remember b [ l ] [ r ] b[l][r] b[l][r] indicates interval [ l , r ] [l,r] [l,r] number remaining after consolidation
You can transfer.
Time complexity O ( n 3 ) O(n^3) O(n3)

## code:

```// Problem: E. Array Shrinking
// Contest: Codeforces - Educational Codeforces Round 83 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1312/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;

typedef long long ll;

const int maxn=2e5+100;

int a[510],b[510][510],dp[510][510];

int main() {
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
dp[i][j]=j-i+1;
if(i==j) b[i][i]=a[i];
}

for(int len=1;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
for(int k=l;k<=r-1;k++){
dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
if(dp[l][k]==1&&dp[k+1][r]==1&&b[l][k]==b[k+1][r]){
dp[l][r]=1;
b[l][r]=b[l][k]+1;
}
}
}
}

cout<<dp[1][n]<<endl;

return 0;
}
```

## Idea:

Consider another representation of the state: d p [ i ] dp[i] dp[i] indicates [ 1 , i ] [1,i] [1,i] the shortest length after merging, then the final answer is [ 1 , n ] [1,n] [1,n]
Transfer, if you say [ k , i ] [k,i] [k,i] can be merged into one number, so obviously d p [ i ] = d p [ k â 1 ] + 1 dp[i]=dp[k-1]+1 dp[i]=dp[kâ1]+1
The problem is how to quickly judge the interval [ k , i ] [k,i] Whether [k,i] can be merged into one number.
Two ideas are extended:

• With the idea of bracket matching, stack is used to judge. The specific method is to enumerate the right endpoints. For each right endpoint, maintain a stack, and then enumerate backwards. If the current element x x x is the same as the stack top element. Pop up the stack top, indicating that the combination of the two becomes x + 1 x+1 x+1. Finally, if the stack size is 1 1 1 indicates that the interval can be combined into one number.
• Use interval d p dp dp to solve, f [ l ] [ r ] f[l][r] f[l][r] indicates interval [ l , r ] [l,r] [l,r] what is the number after consolidation? If yes 0 0 0 means that it cannot be merged into one number. Enumerate the middle points, if you say f [ l ] [ k ] = = f [ k + 1 ] [ r ] f[l][k]==f[k+1][r] f[l][k]==f[k+1][r] f [ l ] [ r ] = f [ l ] [ k ] + 1 f[l][r]=f[l][k]+1 f[l][r]=f[l][k]+1.

The time complexity of the former is O ( n 2 ) O(n^2) O(n2), the latter is O ( n 3 ) O(n^3) O(n3)

## code:

Stack

```// Problem: E. Array Shrinking
// Contest: Codeforces - Educational Codeforces Round 83 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1312/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;

typedef long long ll;

const int maxn=2e5+100;

int a[510],b[510][510],dp[510];

int main() {
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int r=1;r<=n;r++){
dp[r]=dp[r-1]+1;
stack<int>st;
st.push(a[r]);
for(int l=r-1;l;l--){
int now=a[l];
while(1){
if(st.empty()){
st.push(now);break;
}
if(now==st.top()) st.pop(),now++;
else{
st.push(now);break;
}
}
if(st.size()==1) dp[r]=min(dp[r],dp[l-1]+1);
}
}
cout<<dp[n]<<endl;

return 0;
}
```

Interval dp

```// Problem: E. Array Shrinking
// Contest: Codeforces - Educational Codeforces Round 83 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1312/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;

typedef long long ll;

const int maxn=2e5+100;

int a[510],f[510][510],dp[510];

int main() {
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],f[i][i]=a[i];
for(int len=1;len<=n;len++)
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
for(int k=l;k<=r;k++)
if(f[l][k]!=0&&f[l][k]==f[k+1][r])
f[l][r]=f[l][k]+1;
}
memset(dp,0x3f,sizeof dp);
dp[0]=0;
for(int r=1;r<=n;r++)
for(int l=1;l<=r;l++)
if(f[l][r]!=0) dp[r]=min(dp[r],dp[l-1]+1);
cout<<dp[n];
return 0;
}
```

## Summary:

d p dp Different dp states determine different time complexity. For a d p dp For the dp state, there are several solutions.
reference resources:
Blog 1
Blog 2