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 // // Powered by CP Editor (https://cpeditor.org) #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 // // Powered by CP Editor (https://cpeditor.org) #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 // // Powered by CP Editor (https://cpeditor.org) #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