CF1503D Flip the Cards 題解
阿新 • • 發佈:2021-10-29
Link.
Description.
有 \(n\) 張牌,正面反面都寫著兩兩不同的數。
你可以翻轉若干張牌,然後任意排序。
要求正面的數構成單調遞增序列,翻面構成單調遞減序列。
問最少翻轉次數,或判斷無解。
Solution.
先考慮無解情況,如果存在一對 \(a_i\le a_j,b_i\le b_j\) 肯定無解。
所以肯定不存在 \(a_i\le n,b_i\le n\),這樣肯定會有一個 \(a_i>n,b_i>n\),就無解了。
所以相當於如果有解肯定是 \(a_i\in[1,n],b_i\in[n+1,n]\)。
我們可以考慮把 \(a_i(a_i\le n) \rightarrow b_i(b_i>n)\)
相當於我們要把 \(f_i\) 劃分成兩個遞減子序列,次數最小。
考慮找到字首 \(\min\) 和字尾 \(\max\)。
如果 \(\min_x>\max_{x+1}\),那在這邊斷開肯定是可行的且是最優的。
如果不存在 \(\min_x>\max_{x+1}\),那相當於後面肯定有一個比當前大,那當前肯定塞到最小的那一個子序列裡去,這樣是唯一的。
Coding.
點選檢視程式碼
//Coded by leapfrog on 2021.10.29 {{{ //是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了 #include<bits/stdc++.h> using namespace std;typedef long long ll; template<typename T>inline void read(T &x) { x=0;char c=getchar(),f=0; for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1; for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48); f?x=-x:x; } template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}} const int N=400005;int n,a[N],b[N],qz[N],hz[N],fg[N],f[N]; int main() { read(n);for(int i=1;i<=n;i++) read(a[i],b[i]); for(int i=1;i<=n;i++) if(a[i]<=n&&b[i]<=n) return puts("-1"),0; for(int i=1;i<=n;i++) fg[min(a[i],b[i])]=a[i]>b[i]&&(swap(a[i],b[i]),1),f[a[i]]=b[i]; qz[0]=1e9;for(int i=1;i<=n;i++) qz[i]=min(qz[i-1],f[i]); for(int i=n;i>=1;i--) hz[i]=max(hz[i+1],f[i]); int ta=1e9,tb=1e9,sa=0,sb=0,ca=0,cb=0,rs=0; for(int i=1;i<=n;i++) { if(ta>tb) swap(ta,tb),swap(sa,sb),swap(ca,cb); if(f[i]<ta) ta=f[i],sa++,ca+=fg[i]; else if(f[i]<tb) tb=f[i],sb++,cb+=fg[i]; else return puts("-1"),0; if(qz[i]>hz[i+1]) rs+=min(ca+sb-cb,cb+sa-ca),ta=tb=1e9,sa=sb=ca=cb=0; }return printf("%d\n",rs),0; }