瞬间移动

瞬间移动

 

【问题描述】

有一天,暮光闪闪突然对如何将一个整数序列a1,a2,...,an排序为一个不下降序列起了兴趣。身为一只年轻独角兽的她,只能进行一种叫做“单元转换”(unit shift)的操作。换句话说,她可以将序列的最后一个元素移动到它的起始位置:a1,a2,...,an→an,a1,a2,...,an−1
请帮助暮光闪闪计算一下:她对这个序列进行排序所需的最小操作次数是多少?
瞬间移动_第1张图片

 

 

 

【输入格式】

第一行一个整数n(2≤n≤10^5)。
第二行n个整数表示a1,a2,...,an(1≤ai≤10^5)。
 

【输出格式】

如果序列无法被排序,输出-1.
否则输出暮光闪闪对它排序所需要的最少操作次数。
 

【样例输入】

2
2 1
 

【样例输出】

1

【算法分析】

找规律呗:
       首先,我们知道,对于一个不下降子序列,如果我们用折线图把其中的元素大小表示出来,那么这个图像中的每一段的一次函数表达式$y=kx+b$的$k$一定是大于等于“1”的,如图:
瞬间移动_第2张图片

 

       然后我们不妨假设对于这个不下降子序列是由对一个序列进行题中所给的操作得到的,即前几面的若干个数是从末尾移上来的,在这里我们假设红色的一段是移上来的,我们就可以得到移动前的序列的折线统计图:

瞬间移动_第3张图片

 

       那么,我们就可以得出结论了,即对于一个可以通过题中操作变换成为一个不下降子序列且不是单调递增的序列,它一定由两个不下降子序列构成,且第二个子序列的最后一位一定小于等于第一个序列的第一位,否则输出“-1”

       代码实现的话我们只需要找出序列中第一个不下降子序列的结尾的后一位,记录它的下标为“t”,然后从“t”开始往后搜,如果发现后面的序列单调递增,那么输出$n-t+1$,即第一个不下降子序列后面的元素个数

【AC代码】

 
#include
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]1]) {
            t=i;
            break;
        }
    }
    for(int i=t;i){
        if(a[i]>a[i+1]){
            cout<<-1;
            return 0;
        }
    }
    if(a[n]>a[1]){
        cout<<-1;
        return 0;
    }
    cout<1;
}

 

  

你可能感兴趣的:(瞬间移动)