• 题解 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 = '';
    					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 = ''){
    			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 != '')putchar(split);
    		}
    		inline void lf(){putchar('
    ');}
    		~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 - ans);
    }
    int t;
    int main(){
    	io.read(t);
    	while(t--)solve();
    	return 0;
    }
    
  • 相关阅读:
    二叉树(链表形式)
    判断一个非空单链表是否是递增有序的
    指针的异或运算可用于交换两个变量的值
    JavaScript导论
    JavaScript语言的历史
    分享一个分页控件的实现思路
    MVC还是MVVM?或许VMVC更适合WinForm客户端
    基于NPOI的Excel数据导入
    一段用于地址清洗的代码
    模块3之手机号码格式的校验
  • 原文地址:https://www.cnblogs.com/colazcy/p/14032425.html
Copyright © 2020-2023  润新知