1. 程式人生 > 其它 >Codeforces 1367 F2 Flying Sort

Codeforces 1367 F2 Flying Sort

題意

給定一個由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;
}