题意
给一个长度为(n)的数组,你可以有两种操作
- 将某一个数放置在数组开头
- 将某一个数放置在数组结尾
问最小操作多少次可以得到一个非递减数列
(比(F1)难在(n)变大,且数组中元素可以有相同的)
分析
因为数组中的数很大,我们可以将其离散化然后操作,则(a[i])为连续的整数,设(tot)种不同的数,则(1leq a[i] leq tot)
每个数最多操作一次,否则第一次可以不操作,那么我们就要找最多的不需要操作的数,如果不需要操作,则元素的位置不变,如果有这么一组不需要操作的数,我们可以发现,中间的数字是不能插进去的,所以这组数是在排序后仍相邻的数,则要找到最长的子序列,这个子序列在排序后仍然相邻,考虑以下几种情况
- 这组数相同,则没有限制
- 这组数中含有两种数,则要形如(i,i,i,i+1,i+1)这种形式,即排序后仍相邻
- 这组数含有三种以上的数,即形如(i,i,i+1,i+2,i+2,i+3)这种形式,那么中间的数((i+1),(i+2))一定是被取完了,否则其他的(i+1)或者(i+2)要插进去只能重新排序,与中间数字不能插进去不符,即这几个数并不是相邻,例如(i,i+1,i+2,i+1)这种序列,(i,i+1,i+2)并不满足条件,因为(i+1)并没取完
设(dp[i][0])为只取相同的数且以(a[i])为结尾所得到的最长子序列,(dp[i][1])为(a[i])还没取完且所得到的以(a[i])为结尾最长子序列,(dp[i][2])为(a[i])取完且以(a[i])为结尾所得到的最长子序列,我们用(pos[i])表示数字(i)上次出现的位置,因为离散化了,所以数组可以满足,状态转移方程为((r[a[i]])表示(a[i])最后出现的位置,(l[a[i]])表示(a[i])最早出现的位置,(num[a[i]])表示(a[i])的个数,(pos[a[i]])表示上一个(a[i])出现的位置):
dp[i][0] = dp[pos[a[i]]][0] + 1;
dp[i][1] = max(dp[pos[a[i]]][1] + 1, max(dp[pos[a[i] - 1]][0] + 1, dp[pos[a[i] - 1]][2] + 1));
if (i == r[a[i]])
dp[i][2] = dp[l[a[i]]][1] + num[a[i]] - 1;
- (dp[i][0]),方程表示上一个位置的(a[i])接着取
- (dp[i][1]),方程表示上一个(a[i])接着取,或者上一个(a[i]-1)接着取,或者(a[i]-1)已经全部取完后接着取
- (dp[i][2]),方程表示从最早出现的(a[i])开始,后面都只取(a[i])
#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
#define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define int ll
#define ls st<<1
#define rs st<<1|1
#define pii pair<int,int>
#define rep(z, x, y) for(int z=x;z<=y;++z)
#define com bool operator<(const node &b)
using namespace std;
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
const int maxn = (ll) 2e5 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
int T = 1;
int a[maxn], b[maxn];
int dp[maxn][3];
int l[maxn], r[maxn];
int pos[maxn], num[maxn];
void solve() {
int n;
cin >> n;
rep(i, 1, n)cin >> a[i], b[i] = a[i], dp[i][0] = dp[i][1] = dp[i][2] = 0, l[i] = r[i] = 0, num[i] = 0;
sort(b + 1, b + n + 1);
int tot = unique(b + 1, b + n + 1) - (b + 1);
rep(i, 1, n) {
a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
r[a[i]] = i;
if (!l[a[i]])
l[a[i]] = i, pos[a[i]] = i;
++num[a[i]];
}
int maxx = 1;
rep(i, 1, n) {
dp[i][0] = dp[pos[a[i]]][0] + 1;
dp[i][1] = max(dp[pos[a[i]]][1] + 1, max(dp[pos[a[i] - 1]][0] + 1, dp[pos[a[i] - 1]][2] + 1));
if (i == r[a[i]])
dp[i][2] = dp[l[a[i]]][1] + num[a[i]] - 1;
pos[a[i]] = i;
rep(j, 0, 2)maxx = max(maxx, dp[i][j]);
}
cout << n - maxx << '
';
}
signed main() {
start;
cin >> T;
while (T--)
solve();
return 0;
}