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