瞬間移動
【問題描述】
有一天,暮光閃閃突然對如何將一個整數序列a1,a2,...,an排序為一個不下降序列起了興趣。身為一隻年輕獨角獸的她,只能進行一種叫做“單元轉換”(unit shift)的操作。換句話說,她可以將序列的最後一個元素移動到它的起始位置:a1,a2,...,an→an,a1,a2,...,an−1請幫助暮光閃閃計算一下:她對這個序列進行排序所需的最小操作次數是多少?
【輸入格式】
第一行一個整數n(2≤n≤10^5)。第二行n個整數表示a1,a2,...,an(1≤ai≤10^5)。
【輸出格式】
如果序列無法被排序,輸出-1.否則輸出暮光閃閃對它排序所需要的最少操作次數。
【樣例輸入】
22 1
【樣例輸出】
1
【演算法分析】
找規律唄:首先,我們知道,對於一個不下降子序列,如果我們用折線圖把其中的元素大小表示出來,那麼這個影像中的每一段的一次函式表示式$y=kx+b$的$k$一定是大於等於“1”的,如圖:
然後我們不妨假設對於這個不下降子序列是由對一個序列進行題中所給的操作得到的,即前幾面的若干個數是從末尾移上來的,在這裡我們假設紅色的一段是移上來的,我們就可以得到移動前的序列的折線統計圖:
那麼,我們就可以得出結論了,即對於一個可以通過題中操作變換成為一個不下降子序列且不是單調遞增的序列,它一定由兩個不下降子序列構成,且第二個子序列的最後一位一定小於等於第一個序列的第一位,否則輸出“-1”
程式碼實現的話我們只需要找出序列中第一個不下降子序列的結尾的後一位,記錄它的下標為“t”,然後從“t”開始往後搜,如果發現後面的序列單調遞增,那麼輸出$n-t+1$,即第一個不下降子序列後面的元素個數
【AC程式碼】
#include<bits/stdc++.h> using namespace std; int n,a[100010],t; int main() { ios::sync_with_stdio(false); cin>>n; for(int i=1; i<=n; i++) cin>>a[i]; for(int i=2; i<=n; i++) { if(a[i]<a[i-1]) { t=i; break; } } for(int i=t;i<n;i++){ if(a[i]>a[i+1]){ cout<<-1; return 0; } } if(a[n]>a[1]){ cout<<-1; return 0; } cout<<n-t+1; }