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

Posted live4m

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2020ICPC昆明 C.Cities(区间dp)相关的知识,希望对你有一定的参考价值。

题意:

给定长度为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;


以上是关于2020ICPC昆明 C.Cities(区间dp)的主要内容,如果未能解决你的问题,请参考以下文章

2021 ICPC昆明 Stone Games(主席树)

Cities(2020昆明C)

Cities(2020昆明C)

2020ICPC昆明 J.Parallel Sort(思维,规律)

2020ICPC 昆明热身赛 C.Statues(小思维)

ICPC20昆明M——动态开点权值线段树(主席树)