1. 程式人生 > 實用技巧 >題解 CF1367F2 【Flying Sort (Hard Version)】

題解 CF1367F2 【Flying Sort (Hard Version)】

題目連結

Solution CF1367F2 Flying Sort (Hard Version)

題目大意:給定一個序列,每次操作可以選擇將一個元素移到序列頭部或者序列尾部,求最少需要多少次操作可以使這個序列單調不降

dp


分析:要求最小化操作次數,可以變成最多保留多少個數,移動剩下的數使得原序列符合要求。

我們只關心元素之間的相對關係,因此可以進行離散化。

對於我們選取的子序列來說,裡面的元素一定是連續,而且單調不降的,並且對於被“夾在中間的元素”,和它相同的元素一定被全部取完了。

比如我們選取 \(1,2,2,3\),那麼 \(2\) 一定是被取完的,否則我們不可能把它移到中間去。

考慮 \(dp\),記當前位置為 \(i\),當前的數為 \(x\)

那麼當前的決策有:

  • 接著上一個是 \(x\) 的位置接著選
  • 選取前面所有 \(x-1\) 以及當前的 \(x\)
  • 如果 \(x - 1\) 已經全部出現過了,那麼我們選取所有的 \(x-1\),以及它選擇的子序列,以及當前的 \(x\)

對於第一種決策,我們不可能忽略掉被“夾在中間”的元素。因為在上一個是 \(x\) 的位置,如果我們這樣會忽略兩個 \(x\) 之間的 \(x - 1\),那麼在上一個是 \(x\) 的位置,\(x-1\) 一定沒有全部出現過,它的決策只有接著選 \(x\) 或者將 \(x-1\) 作為字首。

#include <cstdio>
#include <cctype>
#include <algorithm>
#pragma GCC optmize(2)
using namespace std;
typedef long long ll;
constexpr int maxn = 2e5 + 100,inf = 0x7fffffff;
struct IO{//-std=c++11,with cstdio and cctype
	private:
		static constexpr int ibufsiz = 1 << 20;
		char ibuf[ibufsiz + 1],*inow = ibuf,*ied = ibuf;
		static constexpr int obufsiz = 1 << 20;
		char obuf[obufsiz + 1],*onow = obuf;
		const char *oed = obuf + obufsiz;
	public:
		inline char getchar(){
			#ifndef ONLINE_JUDGE
				return ::getchar();
			#else
				if(inow == ied){
					ied = ibuf + sizeof(char) * fread(ibuf,sizeof(char),ibufsiz,stdin);
					*ied = '\0';
					inow = ibuf;
				}
				return *inow++;
			#endif
		}
		template<typename T>
		inline void read(T &x){
			static bool flg;flg = 0;
			x = 0;char c = getchar();
			while(!isdigit(c))flg = c == '-' ? 1 : flg,c = getchar();
			while(isdigit(c))x = x * 10 + c - '0',c = getchar();
			if(flg)x = -x;
		}
		template <typename T,typename ...Y>
		inline void read(T &x,Y&... X){read(x);read(X...);}
		inline int readi(){static int res;read(res);return res;}
		inline long long readll(){static long long res;read(res);return res;}
		
		inline void flush(){
			fwrite(obuf,sizeof(char),onow - obuf,stdout);
			fflush(stdout);
			onow = obuf;
		}
		inline void putchar(char c){
			#ifndef ONLINE_JUDGE
				::putchar(c);
			#else
				*onow++ = c;
				if(onow == oed){
					fwrite(obuf,sizeof(char),obufsiz,stdout);
					onow = obuf;
				}
			#endif
		}
		template <typename T>
		inline void write(T x,char split = '\0'){
			static unsigned char buf[64];
			if(x < 0)putchar('-'),x = -x;
			int p = 0;
			do{
				buf[++p] = x % 10;
				x /= 10;
			}while(x);
			for(int i = p;i >= 1;i--)putchar(buf[i] + '0');
			if(split != '\0')putchar(split);
		}
		inline void lf(){putchar('\n');}
		~IO(){
			fwrite(obuf,sizeof(char),onow - obuf,stdout);
		}
}io;
template <typename A,typename B>
inline void chkmin(A &x,const B &y){if(y < x)x = y;}
template <typename A,typename B>
inline void chkmax(A &x,const B &y){if(y > x)x = y;}

int val[maxn],pre[maxn],f[maxn],num[maxn],fir[maxn],cnt[maxn],n;
inline void discretize(){
	static int tmp[maxn];
	for(int i = 1;i <= n;i++)tmp[i] = val[i];
	sort(tmp + 1,tmp + 1 + n);
	int tot = unique(tmp + 1,tmp + 1 + n) - tmp - 1;
	for(int i = 1;i <= n;i++)val[i] = lower_bound(tmp + 1,tmp + 1 + tot,val[i]) - tmp;
}
inline void solve(){
	io.read(n);
	for(int i = 1;i <= n;i++)pre[i] = num[i] = cnt[i] = fir[i] = f[i] = 0;
	for(int i = 1;i <= n;i++)io.read(val[i]);
	discretize();
	for(int i = 1;i <= n;i++){
		num[val[i]]++;
		if(!fir[val[i]])fir[val[i]] = i;
	}
	int ans = 0;
	for(int i = 1;i <= n;i++){
		const int x = val[i];
		chkmax(f[i],f[pre[x]] + 1);
		chkmax(f[i],cnt[x - 1] + 1);
		if(cnt[x - 1] == num[x - 1])chkmax(f[i],f[fir[x - 1]] + cnt[x - 1]);
		pre[x] = i;
		cnt[x]++;
		chkmax(ans,f[i]);
		printf("%d ",f[i]);
	}
	puts("");
	printf("%d\n",n - ans);
}
int t;
int main(){
	io.read(t);
	while(t--)solve();
	return 0;
}