CF1592B Hemose Shopping 題解
阿新 • • 發佈:2021-10-05
題目傳送門
題目大意:有一個長度為 \(n\) 的序列 \(a\) 和數字 \(x\) ,我們每次可以選定兩個數 \(i,j\) 滿足 \(x\le |i-j|\) ,然後交換 \(a_i,a_j\) 。請問經過若干次操作是否能讓序列 \(a\) 遞增。
題目解析:
我們發現當 \(x\le \lfloor \frac{n}{2} \rfloor\) 的時候顯然是成立的,因為我們可以通過第三個數字造作三次來交換任意兩個數字。
當然如果序列 \(a\) 是遞增的話肯定能滿足條件。
所以我們只要考慮 \(x>\lfloor \frac{n}{2} \rfloor\) 並且序列 \(a\) 不是單調遞增的情況。這是我們發現有序列中間一部分的序列是不能動的,而其他部分的序列是可以隨意交換的,方法類似於上面的方法的。
我們發現,這個時候序列中 \(a_{n-x+1},a_{n-x+2},\dots,a_x\)
所以需要不能移動的部分遞增,能任意移動的部分可以通過移動保證序列遞增就可以了。我們只需要統計能移動的部分小於等於 \(a_{n-x+1}\) 和大於等於 \(a_x\) 的數字的個數就可以了。當然注意考慮一下 \(a_{n-x+1}=a_x\) 的情況。
程式碼(去除了快讀&一堆沒用的巨集定義&標頭檔案):
int T,n,x,a[maxn]; int checkup(){ for(RI i=1;i<n;i++) if(a[i]>a[i+1]) return 0; return 1; } int check(){ if(x<=(n>>1)) return 1; if(x>=n) return checkup(); RI i,cnt1=0,cnt2=0,minx=INF,maxx=-INF; x=n-x; for(i=x+1;i<=n-x;i++){ maxx=max(maxx,a[i]); minx=min(minx,a[i]); if(i!=n-x&&a[i]>a[i+1]) return 0; } for(i=1;i<=x;i++) { if(a[i]<minx) cnt1++; if(a[i]==minx) cnt2++; if(minx<a[i]&&a[i]<maxx) return 0; } for(i=n-x+1;i<=n;i++) { if(a[i]<minx) cnt1++; if(a[i]==minx) cnt2++; if(minx<a[i]&&a[i]<maxx) return 0; } if(minx==maxx) return cnt1+cnt2>=x && cnt1<=x; return cnt1+cnt2==x; } int main(){ T=read(); while(T--){ n=read(); x=read(); for(RI i=1;i<=n;i++) a[i]=read(); if(check()) puts("YES"); else puts("NO"); } return 0; }