Codeforces Round #655 (Div. 2) C

题目链接

https://codeforces.com/contest/1372/problem/C

题面

在这里插入图片描述

题意

给定一个长度为 n ( n ≤ 2 e 5 ) n(n\leq2e5) n(n2e5)的数组,你可以任意选择一个区间 [ L , R ] [L,R] [L,R]使得区间内的数都不在原来位置上,问使该数组从小到大排序,最少经过的次数。

思路

不难想到只有三种情况:

1:原数组本身就是从小到大,答案为 0 0 0,因为不需要排序。
2:记录从左边开始第一个不在自己位置的下标为 l l l,从右边边开始第一个不在自己位置的下标为 r r r [ l , r ] [l,r] [l,r]都不在自己的位置上,答案为 1 1 1,因为我们只需要对这部分进行一次排序即可。
3:记录从左边开始第一个不在自己位置的下标为 l l l,从右边边开始第一个不在自己位置的下标为 r r r [ l , r ] [l,r] [l,r]存在至少有一个数在自己的位置上,答案为 2 2 2,因为我们只需要对在自己位置上的这部分进行一次排序之后再将[l,r]进行排序即可。

ps:实在不太理解可以把在自己位置的数赋值为 1 1 1,不在自己位置的赋值为 2 2 2,比如"52341 “->“01110”,题目要求每个位置都不在原位置,那么你肯定要一次改变连续的"111"的位置然后不管咋样乱序都可以一次变为"11111”,这样才是最小次数,又比如:“12435”->“11001”,你肯定要一次改变连续的"00"的位置为"11",正确位置,这样才是最小次数。

参考代码

#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
int main() {
  int t, n;
  scanf("%d", &t);
  while (t--) {
    scanf("%d", &n);
    vector<int> ans(n);
    for (auto &a : ans) {
      scanf("%d", &a);
      a--;
    }
    if (is_sorted(ans.begin(), ans.end())) {
      printf("0\n");
    } else {
      int l = 0, r = n;
      while (l < r && ans[l] == l) {
        l++;
      }
      while (r > l && ans[r - 1] == r - 1) {
        r--;
      }
      bool f = 0;
      for (int i = l; i < r; i++) {
        if (ans[i] == i) {
          f = 1;
          break;
        }
      }
      printf("%d\n", f ? 2 : 1);
    }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuoyanli

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值