codeforces1481 E. Sorting Books(贪心+dp)

大佬题解1
大佬题解2

E. Sorting Books

首先每本书都移动,移动次数是n能够满足题意。如果某些书不用移动,说明把隔开他们中间的书全部抽走后自然成组。

对于每本书全部移动的情况,显然我们可以选择一种颜色的书全部不案,移动别的书,抽走隔开的书后那么他们就会自然成组。

如果存在选择2种书不动的方案,不难知道该两种书出现的区间一定不能相交,因为他们都是自然成组的,如果相交会互相隔断。同理选择3种书不动的方案也一样。

预处理每种书出现的区间 l i , r i l_i,r_i li,ri
状态表示 f i f_i fi表示区间 [ i , n ] [i,n] [i,n]中不需要移动书的最大数量。
状态转移
倒着转移 n → i n\to i ni
对于第 i i i本书,我们可以移动此书,那么 f i = f i + 1 f_i=f_{i+1} fi=fi+1
如果不动此书,那么与此书颜色相同的书也应该不动
如果 l a i = i l_{a_i}=i lai=i,说明 a i a_i ai颜色的书整个区间出现完即可以合并 f i = f r a i + 1 + c n t a i f_i=f_{r_{a_i}+1}+cnt_{a_i} fi=frai+1+cntai,选择多种书(不相交)不动的方案
否则 f i = c u r a i f_i=cur_{a_i} fi=curai,只能选择一种书不动

#define IO ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#pragma GCC optimize(2)
#include
#include
#include
using namespace std;
constexpr int N=500010;
int a[N],f[N],cur[N],n;
int l[N],r[N];
int main()
{
     
    IO;
    cin>>n;
    memset(f,0,(n+1)*sizeof(int));
    memset(l,0x3f,(n+1)*sizeof(int));
    memset(r,-1,(n+1)*sizeof(int));
    for(int i=1;i<=n;i++)
    {
     
        cin>>a[i];
        l[a[i]]=min(l[a[i]],i);
        r[a[i]]=max(r[a[i]],i);
    }
    for(int i=n;i;i--)
    {
     
        cur[a[i]]++;
        // a[i] 移动 
        f[i]=f[i+1];
        // a[i] 不动
        if(i==l[a[i]]) 
            f[i]=max(f[i],cur[a[i]]+f[r[a[i]]+1]);
        else
            f[i]=max(f[i],cur[a[i]]);
    }
    cout<<n-f[1]<<'\n';
    return 0;
}

除夕快乐!

你可能感兴趣的:(dp,贪心,dp)