题意:
给定长度为n的序列a,
一次操作你可以选择一个数值相同的连续区间,将这个区间的数值修改为其他数。
问多少进行多少次操作能使得区间所有数相同。
数据范围:n<=5000,每种a(i)最多出现15次
解法:
首先如果a[i]=a[i-1],那么去重.
去重后的a[]一定相邻不相同.
设a[]的长度为n,
如果a[]互不相同,那么答案显然为n-1.
考虑如何减少答案,显然是选择a[l]=a[r]的区间[l,r],然后将[l+1,r-1]涂成a[l],
这样能减少一次操作,
那么本题的着手点为两端点相同的区间,因为只有这样才能减少操作次数.
令d[l][r]表示[l,r]变成相同颜色的最小操作次数,
令pre[i]表示左边区间上一次出现a[i]的位置.
d[l][r]可以由多种状态转移更新:
1.用d[l+1][r]+1和a[l][r-1]+1更新,这个转移比较显然.
2.如果a[l]=a[r],那么可以用d[l+1][r-1]+1更新,即将[l+1,r-1]变成相同,然后再变成a[r].
3.对于[l+1,r-1]中的位置k,如果满足a[k]=a[r],那么可以用d[l][k-1]+d[k][r]+1更新,
4.对于[l+1,r-1]中的位置k,如果满足a[k]=a[r],同时a[l]=a[k],即a[l]=a[k]=a[r],
那么可以用d[l][k-1]+d[k+1][r]更新,即将[l,k-1]和[k+1,r]都变成a[k].
最后d[1][n]就是答案.
code:
#include<bits/stdc++.h>
#define PI pair<int,int>
using namespace std;
const int maxm=5e3+5;
int d[maxm][maxm];
int pre[maxm];
int a[maxm];
int n;
int dfs(int l,int r){
if(l>=r)return 0;
if(d[l][r]!=-1)return d[l][r];
int ans=(r-l+1)-1;
ans=min(ans,dfs(l+1,r)+1);
ans=min(ans,dfs(l,r-1)+1);
if(a[l]==a[r])ans=min(ans,dfs(l+1,r-1)+1);
for(int k=pre[r];k>l;k=pre[k]){
ans=min(ans,dfs(l,k-1)+dfs(k,r)+1);
if(a[l]==a[r]){
ans=min(ans,dfs(l,k-1)+dfs(k+1,r));
}
}
return d[l][r]=ans;
}
void solve(){
cin>>n;
map<int,int>mp;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==a[i-1]){
i--,n--;
continue;
}
pre[i]=mp[a[i]];
mp[a[i]]=i;
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
d[i][j]=-1;
}
}
int ans=dfs(1,n);
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
int T;cin>>T;
while(T--){
solve();
}
return 0;
}
转载:https://blog.csdn.net/weixin_44178736/article/details/115426033
查看评论