• CODEFORCES 1367F2 FLYING SORT (HARD VERSION)


    题意

    给一个长度为nn的数组,你可以有两种操作

    • 将某一个数放置在数组开头
    • 将某一个数放置在数组结尾

    问最小操作多少次可以得到一个非递减数列

    (比F1F1难在nn变大,且数组中元素可以有相同的)

    分析

    因为数组中的数很大,我们可以将其离散化然后操作,则a[i]a[i]为连续的整数,设tottot种不同的数,则1≤a[i]≤tot1≤a[i]≤tot

    每个数最多操作一次,否则第一次可以不操作,那么我们就要找最多的不需要操作的数,如果不需要操作,则元素的位置不变,如果有这么一组不需要操作的数,我们可以发现,中间的数字是不能插进去的,所以这组数是在排序后仍相邻的数,则要找到最长的子序列,这个子序列在排序后仍然相邻,考虑以下几种情况

    • 这组数相同,则没有限制
    • 这组数中含有两种数,则要形如i,i,i,i+1,i+1i,i,i,i+1,i+1这种形式,即排序后仍相邻
    • 这组数含有三种以上的数,即形如i,i,i+1,i+2,i+2,i+3i,i,i+1,i+2,i+2,i+3这种形式,那么中间的数(i+1i+1,i+2i+2)一定是被取完了,否则其他的i+1i+1或者i+2i+2要插进去只能重新排序,与中间数字不能插进去不符,即这几个数并不是相邻,例如i,i+1,i+2,i+1i,i+1,i+2,i+1这种序列,i,i+1,i+2i,i+1,i+2并不满足条件,因为i+1i+1并没取完

    设dp[i][0]dp[i][0]为只取相同的数且以a[i]a[i]为结尾所得到的最长子序列,dp[i][1]dp[i][1]为a[i]a[i]还没取完且所得到的以a[i]a[i]为结尾最长子序列,dp[i][2]dp[i][2]为a[i]a[i]取完且以a[i]a[i]为结尾所得到的最长子序列,我们用pos[i]pos[i]表示数字ii上次出现的位置,因为离散化了,所以数组可以满足,状态转移方程为(​表示a[i]a[i]最后出现的位置,l[a[i]]l[a[i]]表示a[i]a[i]最早出现的位置,num[a[i]]num[a[i]]表示a[i]a[i]的个数):

    dp[i][0] = dp[pos[a[i]]][0] + 1;
    dp[i][1] = max(dp[pos[a[i]]][1] + 1, max(dp[pos[a[i] - 1]][0] + 1, dp[pos[a[i] - 1]][2] + 1));
    if (i == r[a[i]])
        dp[i][2] = dp[l[a[i]]][1] + num[a[i]] - 1;
    
    • dp[i][0]dp[i][0],方程表示上一个位置的a[i]a[i]接着取
    • dp[i][1]dp[i][1],方程表示上一个a[i]a[i]接着取,或者上一个a[i]−1a[i]−1接着取,或者a[i]−1a[i]−1已经全部取完后接着取
    • dp[i][2]dp[i][2],表示从最早出现的a[i]a[i]开始,后面都只取a[i]a[i]
    #pragma GCC optimize(3, "Ofast", "inline")
    
    #include <bits/stdc++.h>
    
    #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    #define ll long long
    #define int ll
    #define ls st<<1
    #define rs st<<1|1
    #define pii pair<int,int>
    #define rep(z, x, y) for(int z=x;z<=y;++z)
    #define com bool operator<(const node &b)
    using namespace std;
    mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
    const int maxn = (ll) 2e5 + 5;
    const int mod = 998244353;
    const int inf = 0x3f3f3f3f;
    int T = 1;
    int a[maxn], b[maxn];
    int dp[maxn][3];
    int l[maxn], r[maxn];
    int pos[maxn], num[maxn];
    
    void solve() {
        int n;
        cin >> n;
        rep(i, 1, n)cin >> a[i], b[i] = a[i], dp[i][0] = dp[i][1] = dp[i][2] = 0, l[i] = r[i] = 0, num[i] = 0;
        sort(b + 1, b + n + 1);
        int tot = unique(b + 1, b + n + 1) - (b + 1);
        rep(i, 1, n) {
            a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
            r[a[i]] = i;
            if (!l[a[i]])
                l[a[i]] = i, pos[a[i]] = i;
            ++num[a[i]];
        }
        int maxx = 1;
        rep(i, 1, n) {
            dp[i][0] = dp[pos[a[i]]][0] + 1;
            dp[i][1] = max(dp[pos[a[i]]][1] + 1, max(dp[pos[a[i] - 1]][0] + 1, dp[pos[a[i] - 1]][2] + 1));
            if (i == r[a[i]])
                dp[i][2] = dp[l[a[i]]][1] + num[a[i]] - 1;
            pos[a[i]] = i;
            rep(j, 0, 2)maxx = max(maxx, dp[i][j]);
        }
        cout << n - maxx << '
    ';
    }
    
    signed main() {
        cin >> T;
        while (T--)
            solve();
        return 0;
    }
  • 相关阅读:
    ContentProvider总结2
    ContentProvider总结
    ContentObserver的使用完整详细示例
    性能优化之Java(Android)代码优化
    联系人数据库contacts2.db介绍
    contact2.db最强详解
    Android Uri、UriMatcher、ContentUris详解
    Android三种ContentResolver查询方式
    Oracle SQL_杂记
    啥是Restful?
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13309154.html
Copyright © 2020-2023  润新知