题解:CF1312E Array Shrinking

· · 题解

不同于其它题解的 dp 做法。

考虑状态 i,j 表示将前 i 个数进行若干次合并操作,且最终得到的最右侧的数是 j

dp_{i,j} 表示达到状态 i,j 时,最右侧的这个数由几个数合并而来,ans_{i,j} 表示此时 1\sim i 最少合并为几个数,mn_i=\min_{j}(ans_{i,j}),其中状态 i,j 合法。

每次遍历到一个新的数 i 的时候,可以选择:

最后输出 mn_i 即可。

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int a[N];
int dp[N][N<<1],ans[N][N<<1],mn[N];
int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++){
        int x=a[i];
        dp[i][x]=1;
        mn[i]=ans[i][x]=mn[i-1]+1;
        int l=i-1;
        while(dp[l][x]){
            dp[i][x+1]=i-(l-dp[l][x]);
            ans[i][x+1]=ans[l][x];
            mn[i]=min(mn[i],ans[i][x+1]);
            l-=dp[l][x];
            x++;
        }
    }
    cout<<mn[n];
    return 0;
}