[寒假刷题训练1]Codeforces Round #699 (Div. 2)E. Sorting Books

题意:有n本顺序排放的书,第i本书的颜色是 a i a_i ai.你的目标是让所有颜色相同的书排在一起.你每次可以把一本书放到最右边,问最少需要操作多少次.
首先令dp[i]状态为[i,n]且满足条件的最大可不动元素个数,那么答案就为n-dp[1];
显然dp[n]=1,从后往前转移.
有两种情况:
1.不保留当前元素,那么dp[i]=dp[i+1]
2.保留当前元素,那么显然从当前a[i]到最后一个(最右边)a[i]出现的位置之间的所有元素都不能保留,那么最后一个之后的呢?显然可以使得dp[i]=dp[j+1]+cnt(j为最右边的a[i]的位置,cnt为这两者之间的所有a[i]的计数)
注意这种情况只有在当前a[i]为最左边的a[i]时才行,否则dp[i]=cnt[i].

那么为什么呢?cf的题解似乎没有解释清楚这一点.
是因为虽然说是最大保留作为dp状态,但这个dp是有条件的,即保留下来的最右部分可以去除一些数,而不是最右边的部分必须是完整的(即只有完整的非末端才能从右边转移过来的dp继承下去,而任意元素都可以作为末端)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 600000
int a[MAXN];
ll mod=1e9+7;
ll n,m;
int pos[MAXN];
int nxt[MAXN];
int dp[MAXN];
int r[MAXN];
int cnt[MAXN];
int c[MAXN];
int l[MAXN];
int main()
{
    
    
    //freopen("./tt.txt","r",stdin);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=n;i>=1;i--)
    {
    
    
        nxt[i]=pos[a[i]];
        pos[a[i]]=i;
        cnt[i]=++c[a[i]];
        r[a[i]]=max(i,r[a[i]]);
        l[a[i]]=i;
    }
    for(int i=n;i>=1;i--)
    {
    
    
        dp[i]=dp[i+1];
        if(i==l[a[i]])
            dp[i]=max(dp[i],dp[r[a[i]]+1]+cnt[i]);
        else
            dp[i]=max(dp[i],cnt[i]);
    }
    cout<<n-dp[1]<<endl;
}

更接近准确思路的递推如下:
(其余部分相同)

    for(int i=n;i>=1;i--)
    {
    
    
        dp[i]=dp[i+1];
        dp[i]=max(dp[i],cnt[i]);
        if(i==l[a[i]])
            dp[i]=max(dp[i],dp[r[a[i]]+1]+cnt[i]);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43353639/article/details/113776495