专题训练 二分归并排序

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了专题训练 二分归并排序相关的知识,希望对你有一定的参考价值。

二分查找(I)

题目描述

现在有一个长度为n的有序的序列,m次询问,每次会告诉你一个数字x,让你完成以下两种操作:
1.找到第一个大于等于x的值的下标,如果有多个等于的话找到第一个等于的下标
2.找到第一个大于x的值的下标 如果没有就输出NO,保证序列有序。

输入格式

第一行两个正整数n(n <= 100000)代表序列长度和m(m <= 100000)代表询问次数,
第二行n个数字表示有序序列a(其中0 <= ai <= 200000)。接下来m行每行一个数字x(0 <= x <= 200000)。

输出格式

答案输出m行,每行两个数字分别表示答案,两个答案之间用空格隔开。

样例测试

输入:

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

输出:

1 2
2 2
2 3
5 NO
NO NO

参考代码

import java.io.*;

public class Main {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    public static void main(String[] args) {
        int n = nextInt();
        int m = nextInt();
        int[] x = new int[n+1];
        for (int i = 1; i <= n; i++) {
            x[i] = nextInt();
        }
        while(m-- > 0) {
            int y = nextInt();
            int index1 = binarySearch1(x, y);
            int index2 = binarySearch2(x, y);
            if (index1 == -1)
                System.out.print("NO");
            else
                System.out.print(index1);
            if (index2 == -1)
                System.out.print(" NO");
            else
                System.out.print(" "+index2);
            System.out.println();
        }
    }
    public static int binarySearch1(int[] x, int y) {
        int s = 1, e = x.length, mid = 0;

        while (s < e) {
            mid = (s+e)>>1;
            if (x[mid] < y)
                s = mid+1;
            else
                e = mid;
        }
        return (s>x.length-1||s < 1) ? -1: s;
    }
    public static int binarySearch2(int[] x, int y) {
        int s = 1, e = x.length, mid = 0;

        while (s < e) {
            mid = (s+e)>>1;
            if (x[mid] <= y)
                s = mid+1;
            else
                e = mid;
        }
        return (s>x.length-1||s < 1) ? -1: s;
    }
    static int nextInt() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (int)in.nval;
    }
}

二分查找(II)

题目描述

对于一个长度为n的有序序列有以下两种操作:
1.对于给定的值x,找到大于等于x的值,如果有多个等于x的值那么就找到最后一个值为x的序列下标,否则就找到第一个大于x的序列下标
2.对于给定的值x,找到小于等于x的值,如果有多个等于x的值那么就找到最后一个值为x的序列下标,否则就找到第一个小于x的序列下标
如果找不到就输出"NO", 序列下标从1开始,序列保证有序。

输入格式

第一行包含两个正整数n(n <= 100000) 和 m(m <= 100000),分别表示序列大小和询问的次数。第二行是n个由空格隔开的有序序列a(其中0 <= ai <= 200000), 接下来m行每行一个整数x(0 <= x <= 200000)表示要查找的数。

输出格式

输出包含m行,m行包含两个整数x y, 分别代表第一个和第二个操作的答案,或者找不到就输出"NO"。

样例测试

输入:

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

输出:

1 1
2 1
4 4
5 5
NO 5

参考代码

import java.io.*;

public class Main {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    public static void main(String[] args) {
        int n = nextInt();
        int m = nextInt();
        int[] x = new int[n+1];
        for (int i = 1; i <= n; i++) {
            x[i] = nextInt();
        }
        x[0]=-2;
        while(m-- > 0) {
            int y = nextInt();
            int index1 = binarySearch1(x, y);
            int index2 = binarySearch2(x, y);
            if (index1 == -1)
                System.out.print("NO");
            else
                System.out.print(index1);
            if (index2 == -1)
                System.out.print(" NO");
            else
                System.out.print(" "+index2);
            System.out.println();
        }
    }
    public static int binarySearch1(int[] x, int y) {
        int s = 1, e = x.length, mid = 0;

        while (s < e) {
            mid = (s+e)>>1;
            if (x[mid] <= y)
                s = mid+1;
            else
                e = mid;
        }
        return (x[s-1]==y) ? s-1: (s>x.length-1) ? -1: s;
    }
    public static int binarySearch2(int[] x, int y) {
        int s = 1, e = x.length, mid = 0;

        while (s < e) {
            mid = (s+e)>>1;
            if (x[mid] <= y)
                s = mid+1;
            else
                e = mid;
        }
        return (s-1<1) ? -1: s-1;
    }
    static int nextInt() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (int)in.nval;
    }
}

一元三次方程求解

题目描述

在这里插入图片描述

输入格式

一行,4 个实数 a, b, c, d。

输出格式

一行,3 个实根,从小到大输出,并精确到小数点后 2 位。

样例测试

输入:

1 -5 -4 20

输出:

-2.00 2.00 5.00

参考代码

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double a = sc.nextDouble();
        double b = sc.nextDouble();
        double c = sc.nextDouble();
        double d = sc.nextDouble();
        for (double x = -100; x <= 100; x+=0.01) {
            if (Math.abs(a * x * x * x + b * x * x + c * x + d) < 0.01) System.out.printf("%.2f ", x);
        }
    }
}

砍树

题目描述

伐木工人米尔科需要砍倒M米长的木材。这是一个对米尔科来说很容易的工作,因为他有一个漂亮的新伐木机,可以像野火一样砍倒森林。不过,米尔科只被允许砍倒单行树木。

米尔科的伐木机工作过程如下:米尔科设置一个高度参数H(米),伐木机升起一个巨大的锯片到高度H,并锯掉所有的树比H高的部分(当然,树木不高于H米的部分保持不变)。米尔科就行到树木被锯下的部分。

例如,如果一行树的高度分别为20,15,10和17,米尔科把锯片升到15米的高度,切割后树木剩下的高度将是15,15,10和15,而米尔科将从第1棵树得到5米,从第4棵树得到2米,共得到7米木材。

米尔科非常关注生态保护,所以他不会砍掉过多的木材。这正是他为什么尽可能高地设定伐木机锯片的原因。帮助米尔科找到伐木机锯片的最大的整数高度H,使得他能得到木材至少为M米。换句话说,如果再升高1米,则他将得不到M米木材。

输入格式

第1行:2个整数N和M,N表示树木的数量(1<=N<=1000000),M表示需要的木材总长度(1<=M<=2000000000)
第2行:N个整数表示每棵树的高度,值均不超过1000000000。所有木材长度之和大于M,因此必有解。

输出格式

第1行:1个整数,表示砍树的最高高度。

样例测试

输入:

5 20
4 42 40 26 46

输出:

36

参考代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class Main {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    public static void main(String[] args) {
        int n = nextInt();
        int m = nextInt();
        int[] x = new int[n];
        int max = 0;
        for (int i = 0; i < n; i++) {
            x[i] = nextInt();
            if (x[i] > max)
                max = x[i];
        }
        int l = 0, r = max;
        int mid;
        while (l+1 < r) {
            mid = (l+r) >> 1;
            if (check(x, mid, m))
                l = mid;
            else
                r = mid;
        }
        System.out.println(l);
    }
    public static boolean check(int[] x, int h, int m) {
        long sum = 0;
        for (int i = 0; i < x.length; i++) {
            sum += ((x[i]-h)>0?x[i]-h:0);
        }
        return sum >= m;
    }
    static int nextInt() {
        try {
            in.nextToken();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return (int)in.nval;
    }
}

归并排序

import java.util.Arrays;

public class MergeSort {
    public static void main(String[] args) {
        //建立原始数组,可输入
        int[] A = {5,2,4,7,1,3,2,6};
        System.out.println("原始数据: ");
        System.out.println(Arrays.toString(A));
        // new merge_sort().mergeSort(A);
        System.out.println(Arrays.toString(new merge_sort().mergeSort(A)));

    }

    public int[] mergeSort(int[] array) {
        if (array.length == 1)
            return array;
        int num = array.length / 2;
        System.out.println(num);
        int[] left = mergeSort(Arrays.copyOfRange(array,0, num));
        int[] right = mergeSort(Arrays.copyOfRange(array, num, array.length));
        System.out.println(Arrays.toString(left));
        System.out.println(Arrays.toString(right));
        return merge(left, right);
    }

    public int[] merge(int[] left, int[] right) {
        int l = 0, r = 0, i = 0;
        int[] array = new int[left.length+right.length];

        while (l < left.length && r < right.length) {
            if (left[l] < right[r]) {
                array[i] = left[l];
                l++;
            } else {
                array[i] = right[r];
                r++;
            }
            i++;
        }
        while (l < left.length) {
            array[i] = left[l];
            l++;
            i++;
        }
        while (r < right.length) {
            array[i] = right[r];
            r++;
            i++;
        }

        return array;
    }
}

逆序对

题目描述

在这里插入图片描述

输入格式

第一行,一个数 n,表示序列中有 n个数。
第二行 nn 个数,表示给定的序列。序列中每个数字不超过 10^9。

输出格式

输出序列中逆序对的数目。

样例测试

输入:

6
5 4 2 6 3 1

输出:

11

参考代码

import java.io.*;

public class Main {
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter out = new PrintWriter(new<

以上是关于专题训练 二分归并排序的主要内容,如果未能解决你的问题,请参考以下文章

排序算法专题之归并排序

实验4二分归并排序

排序专题之归并排序

分治算法 ------二分归并排序

排序算法专题:快排和归并排序

数组--二分查找 专题训练