图片说明
题意:把一段相同的形状变成其它任意一个形状,需要使用一次魔法,问最少使用多少魔法能使全是同一个形状。

思路:
先把连续的缩成一个连续段,假设缩点后有m个段,如果每个互不相同,答案显然是m-1,不管怎样合都对答案没有影响。如果在合并两个区间时,两个区间的左、右端点的值相同,那么可以通过将中间的值赋值成该值,可以省去一步。
假设表示合并区间的最小代价,表示与相同的点的下标。枚举有没有参与省去的过程,即。同时注意考虑一下左端点相同的情况:

MyCode:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+7,maxm=2e5+7;
typedef long long int ll;
typedef unsigned long long ull;
int a[5001],f[5001][5001],u[5001],lt[5001];
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T,n;
    cin>>T;
    while(T--) {
        cin>>n;
        for(int i=1;i<=n;++i) {
            cin>>a[i];
            if(a[i]==a[i-1]) --i,--n;
            u[a[i]]=0;
        }
        for(int i=1;i<=n;++i) {
            lt[i]=u[a[i]];
            u[a[i]]=i;
            f[i][i]=0;
        }
        for(int len=2;len<=n;++len)
        for(int l=1,r=l+len-1;l<=n-len+1;++l,++r) {
            f[l][r]=f[l][r-1]+1;
            for(int k=lt[r];k>=l;k=lt[k])
                f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
        }
        cout<<f[1][n]<<'\n';
    }
    return 0;;
}