[思維] Codeforces Round #591 D. Sequence Sorting

題意:給定一序列,每次可以選擇一個數,並將序列內所有數放在序列最前面/最後面,問使序列有序的最小操作數

 考慮最差情況肯定是不同數字個數 - 1(完全無序和區間交叉)

考慮交換次數不容易思考,可以反向考慮最多的不用交換就有序的數字,

思考發現,當兩個數字x < y,數字區間無交叉且數值間沒有第三個數字時,這兩個數字不用動就有序,

那麼將題目數字抽象爲線段並離散,使得最大連續數值不交(小數區間在前 大數區間在後)

總減x即可

/*
    Zeolim - An AC a day keeps the bug away
*/
 
//#pragma GCC optimize(2)
//#pragma GCC ("-W1,--stack=128000000")
#include <bits/stdc++.h>
using namespace std;
#define mp(x, y) make_pair(x, y)
#define fr(x, y, z) for(int x = y; x < z; ++x)
#define pb(x) push_back(x)
#define mem(x, y) memset(x, y, sizeof(x))
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef std::pair <int, int> pii;
typedef std::vector <int> vi;
//typedef __int128 ill;
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MOD = 386910137;
const ull P = 13331; 
const int MAXN = 1e6 + 100;

int arr[MAXN] = {0};

struct lsh
{
	int v[MAXN], vl; 
	lsh() { vl = 0; }
	void pb(int val) { v[vl++] = val; } //????? 
	void init() { sort(v, v + vl); vl = unique(v, v + vl) - v; } //?????,???? 
	int find(int val) { return lower_bound(v, v + vl, val) - v;} //??????
	int get(int pos) { return v[pos]; }  //???????? 
};

int mx[MAXN][2];
int dp[MAXN] = {0};

int main()
{  
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    //freopen("d:\out.txt","w",stdout);
    //freopen("d:\in.txt","r",stdin);
   	
   	int n;
   	
   	cin >> n;

	while(n--)
	{
		int len;
		
		cin >> len;
		
		lsh V;
		
		for(int i = 0; i < len; ++i)
		{
			cin >> arr[i];
			V.pb(arr[i]);
			dp[i] = 1;
		}
			
		V.init();
		
		for(int i = 0; i < V.vl; ++i)
		{
			mx[i][0] = 0x3f3f3f3f;
			mx[i][1] = 0;
		}
		
		len = unique(arr, arr + len) - arr;
		
		for(int i = 0; i < len; ++i)
		{
			arr[i] = V.find(arr[i]);
			mx[arr[i]][0] = min(mx[arr[i]][0], i); //變爲線段
			mx[arr[i]][1] = max(mx[arr[i]][1], i);
		}
		
//		for(int i = 0; i < len; ++i)
//		{
//			cout << mx[arr[i]][0] << ' ' << mx[arr[i]][0] << '\n';
//		}
		
	//	cout << '\n';
		
		int cut = 1;
		
		for(int i = 0; i < len; ++i)
		{
			if(arr[i] == 0) continue; 
			if(mx[arr[i] - 1][1] < mx[arr[i]][0]) //計算最大連續遞增不交線段數
			{
				dp[arr[i]] = dp[arr[i] - 1] + 1;
				cut = max(cut, dp[arr[i]]);
			}
		}
		
		cout << V.vl - cut << '\n';
		
	}
   	
	return 0;
}

/*
2
00001000
0001000
000000000000000000000000000100000
000000000000000000000000000000000100000000000000000000000000000000000001001000000000000000000000000
00000000000000000000000000000000010000000000000000000000000000000000000100100
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章