|
|
package class32;
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
|
// 给定一个数组arr,arr[i] = j,表示第i号试题的难度为j。给定一个非负数M
|
|
|
// 想出一张卷子,对于任何相邻的两道题目,前一题的难度不能超过后一题的难度+M
|
|
|
// 返回所有可能的卷子种数
|
|
|
public class ExaminationPaperWays {
|
|
|
|
|
|
// 纯暴力方法,生成所有排列,一个一个验证
|
|
|
public static int ways1(int[] arr, int m) {
|
|
|
if (arr == null || arr.length == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
return process(arr, 0, m);
|
|
|
}
|
|
|
|
|
|
public static int process(int[] arr, int index, int m) {
|
|
|
if (index == arr.length) {
|
|
|
for (int i = 1; i < index; i++) {
|
|
|
if (arr[i - 1] > arr[i] + m) {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
return 1;
|
|
|
}
|
|
|
int ans = 0;
|
|
|
for (int i = index; i < arr.length; i++) {
|
|
|
swap(arr, index, i);
|
|
|
ans += process(arr, index + 1, m);
|
|
|
swap(arr, index, i);
|
|
|
}
|
|
|
return ans;
|
|
|
}
|
|
|
|
|
|
public static void swap(int[] arr, int i, int j) {
|
|
|
int tmp = arr[i];
|
|
|
arr[i] = arr[j];
|
|
|
arr[j] = tmp;
|
|
|
}
|
|
|
|
|
|
// 时间复杂度O(N * logN)
|
|
|
// 从左往右的动态规划 + 范围上二分
|
|
|
public static int ways2(int[] arr, int m) {
|
|
|
if (arr == null || arr.length == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
Arrays.sort(arr);
|
|
|
int all = 1;
|
|
|
for (int i = 1; i < arr.length; i++) {
|
|
|
all = all * (num(arr, i - 1, arr[i] - m) + 1);
|
|
|
}
|
|
|
return all;
|
|
|
}
|
|
|
|
|
|
// arr[0..r]上返回>=t的数有几个, 二分的方法
|
|
|
// 找到 >=t 最左的位置a, 然后返回r - a + 1就是个数
|
|
|
public static int num(int[] arr, int r, int t) {
|
|
|
int i = 0;
|
|
|
int j = r;
|
|
|
int m = 0;
|
|
|
int a = r + 1;
|
|
|
while (i <= j) {
|
|
|
m = (i + j) / 2;
|
|
|
if (arr[m] >= t) {
|
|
|
a = m;
|
|
|
j = m - 1;
|
|
|
} else {
|
|
|
i = m + 1;
|
|
|
}
|
|
|
}
|
|
|
return r - a + 1;
|
|
|
}
|
|
|
|
|
|
// 时间复杂度O(N * logV)
|
|
|
// 从左往右的动态规划 + IndexTree
|
|
|
public static int ways3(int[] arr, int m) {
|
|
|
if (arr == null || arr.length == 0) {
|
|
|
return 0;
|
|
|
}
|
|
|
int max = Integer.MIN_VALUE;
|
|
|
int min = Integer.MAX_VALUE;
|
|
|
for (int num : arr) {
|
|
|
max = Math.max(max, num);
|
|
|
min = Math.min(min, num);
|
|
|
}
|
|
|
IndexTree itree = new IndexTree(max - min + 2);
|
|
|
Arrays.sort(arr);
|
|
|
int a = 0;
|
|
|
int b = 0;
|
|
|
int all = 1;
|
|
|
itree.add(arr[0] - min + 1, 1);
|
|
|
for (int i = 1; i < arr.length; i++) {
|
|
|
a = arr[i] - min + 1;
|
|
|
b = i - (a - m - 1 >= 1 ? itree.sum(a - m - 1) : 0);
|
|
|
all = all * (b + 1);
|
|
|
itree.add(a, 1);
|
|
|
}
|
|
|
return all;
|
|
|
}
|
|
|
|
|
|
// 注意开始下标是1,不是0
|
|
|
public static class IndexTree {
|
|
|
|
|
|
private int[] tree;
|
|
|
private int N;
|
|
|
|
|
|
public IndexTree(int size) {
|
|
|
N = size;
|
|
|
tree = new int[N + 1];
|
|
|
}
|
|
|
|
|
|
public int sum(int index) {
|
|
|
int ret = 0;
|
|
|
while (index > 0) {
|
|
|
ret += tree[index];
|
|
|
index -= index & -index;
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
public void add(int index, int d) {
|
|
|
while (index <= N) {
|
|
|
tree[index] += d;
|
|
|
index += index & -index;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 为了测试
|
|
|
public static int[] randomArray(int len, int value) {
|
|
|
int[] arr = new int[len];
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
arr[i] = (int) (Math.random() * (value + 1));
|
|
|
}
|
|
|
return arr;
|
|
|
}
|
|
|
|
|
|
// 为了测试
|
|
|
public static void main(String[] args) {
|
|
|
int N = 10;
|
|
|
int value = 20;
|
|
|
int testTimes = 1000;
|
|
|
System.out.println("测试开始");
|
|
|
for (int i = 0; i < testTimes; i++) {
|
|
|
int len = (int) (Math.random() * (N + 1));
|
|
|
int[] arr = randomArray(len, value);
|
|
|
int m = (int) (Math.random() * (value + 1));
|
|
|
int ans1 = ways1(arr, m);
|
|
|
int ans2 = ways2(arr, m);
|
|
|
int ans3 = ways3(arr, m);
|
|
|
if (ans1 != ans2 || ans1 != ans3) {
|
|
|
System.out.println("出错了!");
|
|
|
System.out.println(ans1);
|
|
|
System.out.println(ans2);
|
|
|
System.out.println(ans3);
|
|
|
}
|
|
|
}
|
|
|
System.out.println("测试结束");
|
|
|
}
|
|
|
|
|
|
}
|