CodeForces 1367F2 Flying Sort (Hard Version)


題意

給一個長度為\(n\)的數組,你可以有兩種操作

  • 將某一個數放置在數組開頭
  • 將某一個數放置在數組結尾

問最小操作多少次可以得到一個非遞減數列

(比\(F1\)難在\(n\)變大,且數組中元素可以有相同的)

分析

因為數組中的數很大,我們可以將其離散化然后操作,則\(a[i]\)為連續的整數,設\(tot\)種不同的數,則\(1\leq a[i] \leq tot\)

每個數最多操作一次,否則第一次可以不操作,那么我們就要找最多的不需要操作的數,如果不需要操作,則元素的位置不變,如果有這么一組不需要操作的數,我們可以發現,中間的數字是不能插進去的,所以這組數是在排序后仍相鄰的數,則要找到最長的子序列,這個子序列在排序后仍然相鄰,考慮以下幾種情況

  • 這組數相同,則沒有限制
  • 這組數中含有兩種數,則要形如\(i,i,i,i+1,i+1\)這種形式,即排序后仍相鄰
  • 這組數含有三種以上的數,即形如\(i,i,i+1,i+2,i+2,i+3\)這種形式,那么中間的數(\(i+1\)\(i+2\))一定是被取完了,否則其他的\(i+1\)或者\(i+2\)要插進去只能重新排序,與中間數字不能插進去不符,即這幾個數並不是相鄰,例如\(i,i+1,i+2,i+1\)這種序列,\(i,i+1,i+2\)並不滿足條件,因為\(i+1\)並沒取完

\(dp[i][0]\)為只取相同的數且以\(a[i]\)為結尾所得到的最長子序列,\(dp[i][1]\)\(a[i]\)還沒取完且所得到的以\(a[i]\)為結尾最長子序列,\(dp[i][2]\)\(a[i]\)取完且以\(a[i]\)為結尾所得到的最長子序列,我們用\(pos[i]\)表示數字\(i\)上次出現的位置,因為離散化了,所以數組可以滿足,狀態轉移方程為(​\(r[a[i]]\)表示\(a[i]\)最后出現的位置,\(l[a[i]]\)表示\(a[i]\)最早出現的位置,\(num[a[i]]\)表示\(a[i]\)的個數,\(pos[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]\),方程表示上一個位置的\(a[i]\)接着取
  • \(dp[i][1]\),方程表示上一個\(a[i]\)接着取,或者上一個\(a[i]-1\)接着取,或者\(a[i]-1\)已經全部取完后接着取
  • \(dp[i][2]\),方程表示從最早出現的\(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 << '\n';
}

signed main() {
    start;
    cin >> T;
    while (T--)
        solve();
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM