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;
}
标签:Sort,F2,const,int,typedef,long,1367,序列,include 来源: https://www.cnblogs.com/luoyicong/p/16026898.html