Codeforces 1367 F2 Flying Sort
阿新 • • 發佈:2022-03-19
題意
給定一個由n個正整數構成的序列(序列中可能有相同元素),現在有兩種操作:
1.選取序列中的任意一項,將其放置於序列首位;
2.選取序列中的任意一項,將其放置於序列末尾;
每個數最多操作一次.現需要將該序列變成不下降序列,請問至少需要操作幾次。
分析
由於這些數只和大小關係有關,離散化一下,將值域變為\([1, n]\)。
每個數如果要移動,最多隻會移動一次。
那麼,次數 = n - 不移動的數字個數。
我們考慮最大化不用移動的數字個數。
不用移動,意味著這些數在原陣列中是有序的,而且值域上是連續的,而且每個數大於等於前一個數。
程式碼
//#pragma GCC optimize(2) #include<bits/stdc++.h> #include<sstream> #include<string> #include<cstring> #include<cmath> #include<map> #include<iomanip> #include<bitset> #include<unordered_set> #include<unordered_map> #define IOS cin.tie(0), ios::sync_with_stdio(false) #define x first #define y second #define int long long using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef pair<double, double> pdd; const int N = 2e6 + 10, M = N * 2, INF = 0x3f3f3f3f, mod = 1e9 + 7; const double eps = 1e-8; const double pi = acos(-1.0); const int P = 131; int a[N], b[N]; int f[N]; // f[i] 表示以 a[i] 為不移動序列的最後一個數的最大序列長度 int cnt[N]; // 總次數 int tot[N]; // 當前次數 int fir[N]; // 第一次出現的位置 int last[N];// 上一次出現的位置 int n; void solve() { cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> a[i], b[i] = a[i]; sort(b + 1, b + n + 1); int m = unique(b + 1, b + n + 1) - b - 1; // 離散化 for(int i = 1 ; i <= n ; i ++) a[i] = lower_bound(b + 1, b + m + 1, a[i]) - b, cnt[a[i]] ++; int res = 0; for(int i = 1 ; i <= n ; i ++){ int x = a[i]; // x - 1 已經滿了 x 接到 x - 1 後面 if(tot[x - 1] == cnt[x - 1]) f[i] = max(f[i], f[fir[x - 1]] + cnt[x - 1]); // x 出現過 x 接到 x 上次出現後面 if(last[x]) f[i] = max(f[i], f[last[x]] + 1); // x - 1 還沒有滿 那麼 x - 1 一定是作為不移動序列的最小的數 if(last[x - 1]) f[i] = max(f[i], tot[x - 1] + 1); f[i] = max(f[i], 1ll); res = max(res, f[i]); last[x] = i; if(!fir[x]) fir[x] = i; tot[x] ++; } // 總數 減去 不移動序列最大值 就是 答案 cout << n - res << "\n"; } signed main() { IOS; // init(); int T = 1; // cin >> T; while(T --) { solve(); } return 0; }