[思维] 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
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值