題解 CF1367F2 【Flying Sort (Hard Version)】
阿新 • • 發佈:2020-11-24
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; }