歷屆試題 小朋友排隊

肖有量發表於2020-09-30

@ 藍橋杯 練習系統 歷屆試題 PREV-31

資源限制

時間限制:1.0s 記憶體限制:256.0MB


問題描述

n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。

每個小朋友都有一個不高興的程度。開始的時候,所有小朋友的不高興程度都是0。

如果某個小朋友第一次被要求交換,則他的不高興程度增加1,如果第二次要求他交換,則他的不高興程度增加2(即不高興程度為3),依次類推。當要求某個小朋友第k次交換時,他的不高興程度增加k。

請問,要讓所有小朋友按從低到高排隊,他們的不高興程度之和最小是多少。

如果有兩個小朋友身高一樣,則他們誰站在誰前面是沒有關係的。


輸入格式

輸入的第一行包含一個整數n,表示小朋友的個數。
第二行包含 n 個整數 H1 H2 … Hn,分別表示每個小朋友的身高。


輸出格式

輸出一行,包含一個整數,表示小朋友的不高興程度和的最小值。


測試樣例1

Input:
3
3 2 1

Output:
9

Explanation:
首先交換身高為3和2的小朋友,再交換身高為3和1的小朋友,再交換身高為2和1的小朋友,每個小朋友的不高興程度都是3,總和為9。

資料規模與約定

對於10%的資料, 1<=n<=10;
對於30%的資料, 1<=n<=1000;
對於50%的資料, 1<=n<=10000;
對於100%的資料,1<=n<=100000,0<=Hi<=1000000。



記錄每個數字能構成逆數對的次數

先暴力一波:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    public static void main(String[] args) {
        InputReader in = new InputReader(System.in, " \n");
        int n = in.nextInt();
        long cnt = 0;
        int[] a = new int[n], b = new int[n], c = new int[n];
        a[0] = in.nextInt();
        for (int i = 1; i < n; i++) {
            a[i] = in.nextInt();
            c[i] = c[i - 1] + i;
        }
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j < n; j++) if (a[i] > a[j]) { b[i]++; b[j]++; }
        for (int i = 0; i < n; i++) cnt += c[b[i]];
        System.out.print(cnt);
    }

    static class InputReader { . . . }
}

70分,害行,但我得有技術人的秉持

先上個我會的,節點大小平衡樹

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    static Node[] tree;
    static int[] unhappy;

    public static void main(String[] args) {
        InputReader in = new InputReader(System.in, " \n");
        int n = in.nextInt();
        tree = new Node[n + 1];
        unhappy = new int[n + 1];
        unhappy[1] = 1;
        tree[0] = new Node(0, 0);
        tree[1] = new Node(in.nextInt(), 1);
        for (int i = 2; i <= n; i++) {
            tree[i] = new Node(in.nextInt(), 1);
            unhappy[i] = unhappy[i - 1] + i;
            insert(1, i);
        }
        System.out.print(calc(1));
    }

    static long calc(int n) {
        if (n == 0) return 0;
        return calc(tree[n].left) + calc(tree[n].right)+ unhappy[tree[n].k];
    }

    static void insert(int n, int v) {
        tree[n].s++;
        if (tree[n].v <= tree[v].v) {
            if (tree[n].right != 0) insert(tree[n].right, v);
            else tree[n].right = v;
            maintain(n, false);
        } else {
            tree[v].k += tree[tree[n].right].s + 1;
            add(tree[n].right);
            tree[n].k++;
            if (tree[n].left != 0) insert(tree[n].left, v);
            else tree[n].left = v;
            maintain(n, true);
        }
    }

    static void LeftRotate(int node) {
        Node temp = tree[node];
        int r = temp.right;
        tree[r].s = temp.s;
        temp.right = tree[r].left;
        temp.s = tree[temp.left].s + tree[temp.right].s + 1;
        tree[r].left = r;
        tree[node] = tree[r];
        tree[r] = temp;
    }

    static void RightRotate(int node) {
        Node temp = tree[node];
        int l = temp.left;
        tree[l].s = temp.s;
        temp.left = tree[l].right;
        temp.s = tree[temp.left].s + tree[temp.right].s + 1;
        tree[l].right = l;
        tree[node] = tree[l];
        tree[l] = temp;
    }

    static void maintain(int node, boolean flag) {
        if (flag) {
            if (tree[tree[tree[node].left].left].s > tree[tree[node].right].s) RightRotate(node);
            else if (tree[tree[tree[node].left].right].s > tree[tree[node].right].s) {
                LeftRotate(tree[node].left);
                RightRotate(node);
            } else return;
        } else {
            if (tree[tree[tree[node].right].right].s > tree[tree[node].left].s) LeftRotate(node);
            else if (tree[tree[tree[node].right].left].s > tree[tree[node].left].s) {
                RightRotate(tree[node].right);
                LeftRotate(node);
            } else return;
        }
        maintain(tree[node].left, true);
        maintain(tree[node].right, false);
    }

    static void add(int n) {
        if (n == 0) return;
        tree[n].k++;
        add(tree[n].left);
        add(tree[n].right);
    }

    static class Node {

        int v, s, k, left, right;

        Node(int value, int size) {
            this.v = value;
            this.s = size;
        }
    }

    static class InputReader { . . . }
}

在這裡插入圖片描述
對比通過的最後一個用例,提升還是明顯的,但很遺憾,還是70分

我想到一個點子,打個懶標記降低時間複雜程度

先吃飯

相關文章