飞道的博客

2020ICPC昆明 C.Cities(区间dp)

356人阅读  评论(0)

题意:

给定长度为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
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场