CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!), E题 --- 题解

目录

题目大意:

思路解析:

代码:


Problem - E - Codeforces

题目大意:

现在给你一个排列,排列的定义是如果排列长度为n,则他应该出现1-n的每个数字一次,但是顺序是无序的,现在问你通过旋转使得这个排列变为有序的,每个位置需要多少次旋转就可以让他变为有序。旋转操作定义为:让现在排列在不是有序的位置进行左移。例如:3 2 4 1 5,现在有序的位置 2 和 5,所以我们让 1 3 4这上面位置的数字进行旋转,旋转一次后,数列变为 1 2 3 4 5。

思路解析:

我们现在知道了,我们只能进行旋转,我们需要得到它这个位置进行旋转的次数,因为每次旋转一次就会左移一次,其实就是看它对应位置的距离。                                                                               给出一个例子: 

2 1 4 6 5 3
1 2 3 4 5 6

 1 和 1 的位置距离5,

2 和 2 的位置距离1,

3 和 3 的位置距离3,这里 包括了 2 和 2 的距离

4 和 4 的位置距离1,

5 和 5 的位置距离0,

6 和 6 的位置距离2。例如 这里包括了5和5的距离

但是这些距离其实包括了已经不需要移动的距离,或者在移动过程中,有些距离已经不需要移动了,这是需要减去的。所以我们可以通过每个位置上面的ai,来计算它前往的有序位置距离它当前位置的距离。                                                                                                                                      计算公式为 

  1. ai >= i,  x = ai - i
  2. ai < i,    x = ai + n - i

通过上面分析,我们知道这样的距离其实是包括了一些多余的距离(多余的距离通过上面分析我们知道,就是在旋转时,比我们先达到终点的点),那我们可以把这个距离看作一个线段,如果它比我们先达到终点,则这个线段应该完全被我的线段包含。如 6 -> 6 的线段为 4 - 6. 5 -> 5 的线段为 5 - 5. 6 -> 6 的线段完全包含5 -> 5 的线段,所以 6 -> 6 的线段距离为 6 - 4 - 1。完全包含几个线段就减去几。这里线段的查询和更新使用二叉索引数完成。

因为ai < i情况下的线段为 i --- ai + n 。因为有些线段跨越了n,这将ai >= i情况下的线段分为两个:i --- ai,i+n  --- ai+n。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.Arrays;
import java.util.Scanner;

/**
 * @ProjectName: study3
 * @FileName: Ex27
 * @author:HWJ
 * @Data: 2023/11/26 0:48
 */
public class Ex27 {
    static int[] f;
    static int n;
    public static void main(String[] args) throws IOException {
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        in.nextToken();
        int t = (int)in.nval;
        for (int o = 0; o < t; o++) {
            in.nextToken();
            n =(int)in.nval;
            int[] res = new int[n + 1];
            int[] arr = new int[n + 1];
            f = new int[2 * n + 5];
            int[][] rgs = new int[2 * n + 5][2];
            int p = 0;
            for (int i = 1; i <= n; i++) {
                in.nextToken();
                arr[i] = (int)in.nval;
                if (i <= arr[i]){
                    rgs[p][0] = i;
                    rgs[p++][1] = arr[i];
                    rgs[p][0] = i + n;
                    rgs[p++][1] = arr[i] + n;
                }else {
                    rgs[p][0] = i;
                    rgs[p++][1] = arr[i] + n;
                }
            }
            Arrays.sort(rgs, 0, p, ((o1, o2) -> {
                return o2[0] - o1[0];
            }));
            for (int i = 0; i < p; i++) {
                if (rgs[i][0] <= n){
                    res[arr[rgs[i][0]]] = rgs[i][1] - rgs[i][0] - (qre(rgs[i][1]) - qre(rgs[i][0] - 1));
                }
                incre(rgs[i][1]);
            }
            for (int i = 1; i <= n; i++) {
                System.out.print(res[i] + " ");
            }
            System.out.println();
        }
    }

    public static int qre(int x){
        int res = 0;
        for (; x > 0; x -= x & -x) {
            res += f[x];
        }
        return res;
    }

    public static void incre(int x){
        for (; x <= 2 * n; x += x & -x) {
            f[x] += 1;
        }
    }
}

你可能感兴趣的:(算法)