From e5bfd19b9f00f17256dcd3a173b13bbcd56073de Mon Sep 17 00:00:00 2001 From: algorithmzuo Date: Sat, 18 Jun 2022 11:03:09 +0800 Subject: [PATCH] modify code --- ...sMain.java => Code02_SnacksWaysMain1.java} | 17 +-- src/class39/Code02_SnacksWaysMain2.java | 135 ++++++++++++++++++ 2 files changed, 144 insertions(+), 8 deletions(-) rename src/class39/{Code02_SnacksWaysMain.java => Code02_SnacksWaysMain1.java} (88%) create mode 100644 src/class39/Code02_SnacksWaysMain2.java diff --git a/src/class39/Code02_SnacksWaysMain.java b/src/class39/Code02_SnacksWaysMain1.java similarity index 88% rename from src/class39/Code02_SnacksWaysMain.java rename to src/class39/Code02_SnacksWaysMain1.java index a224dc7..f282098 100644 --- a/src/class39/Code02_SnacksWaysMain.java +++ b/src/class39/Code02_SnacksWaysMain1.java @@ -1,17 +1,18 @@ -//不要拷贝包信息的内容 +// 不要拷贝包信息的内容 package class39; -//本文件是Code02_SnacksWays问题的牛客题目解答 -//但是用的分治的方法 -//这是牛客的测试链接: -//https://www.nowcoder.com/questionTerminal/d94bb2fa461d42bcb4c0f2b94f5d4281 -//把如下的全部代码拷贝进编辑器(java) -//可以直接通过 +// 课堂版本 +// 本文件是Code02_SnacksWays问题的牛客题目解答 +// 但是用的分治的方法 +// 这是牛客的测试链接: +// https://www.nowcoder.com/questionTerminal/d94bb2fa461d42bcb4c0f2b94f5d4281 +// 把如下的全部代码拷贝进编辑器(java) +// 可以直接通过 import java.util.Map.Entry; import java.util.Scanner; import java.util.TreeMap; -public class Code02_SnacksWaysMain { +public class Code02_SnacksWaysMain1 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); diff --git a/src/class39/Code02_SnacksWaysMain2.java b/src/class39/Code02_SnacksWaysMain2.java new file mode 100644 index 0000000..0d4bf87 --- /dev/null +++ b/src/class39/Code02_SnacksWaysMain2.java @@ -0,0 +1,135 @@ +// 不要拷贝包信息的内容 +package class39; + +//优化版本 +import java.util.Arrays; +import java.util.Scanner; + +public class Code02_SnacksWaysMain2 { + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + while (sc.hasNext()) { + size = sc.nextInt(); + long w = (long) sc.nextInt(); + for (int i = 0; i < size; i++) { + arr[i] = (long) sc.nextInt(); + } + long ways = ways(w); + System.out.println(ways); + } + sc.close(); + } + + // 用来收集所有输入的数字 + public static long[] arr = new long[31]; + public static int size = 0; + // 用来生成左部分可能的所有累加和 + public static long[] leftSum = new long[1 << 16]; + // 准备的数组可能用不完,左部分生成了多少累加和,用leftSize表示 + public static int leftSize = 0; + // 用来生成右部分可能的所有累加和 + public static long[] rightSum = new long[1 << 16]; + // 准备的数组可能用不完,左部分生成了多少累加和,用leftSize表示 + public static int rightSize = 0; + + public static long ways(long w) { + if (size == 0) { + return 0; + } + if (size == 1) { + return arr[0] <= w ? 2 : 1; + } + // 求中点 + int mid = size >> 1; + // 生成左侧的累加和 + leftSize = 0; + dfsLeft(0, mid + 1, 0L); + // 生成右侧的累加和 + rightSize = 0; + dfsRight(mid + 1, size, 0L); + // 把左侧累加和排序 + Arrays.sort(leftSum, 0, leftSize); + // 把右侧累加和排序 + Arrays.sort(rightSum, 0, rightSize); + // 解释一下,接下来的流程。 + // 举个例子,比如: + // 左侧累加和是:{0, 1, 1, 1, 2, 2, 3, 4, 4} + // 右侧累加和是:{0, 1, 2, 3, 3, 3, 4, 4, 5} + // w = 5 + // 左侧严格得到0的方法数:1 + // 右侧得到<=5的方法数(二分求出):9 + // 1 * 9 + // 左侧严格得到1的方法数:3 + // 右侧得到<=4的方法数(二分求出):8 + // 3 * 8 + // 左侧严格得到2的方法数:2 + // 右侧得到<=3的方法数(二分求出):6 + // 2 * 6 + // 左侧严格得到3的方法数:1 + // 右侧得到<=2的方法数(二分求出):3 + // 1 * 3 + // 左侧严格得到4的方法数:2 + // 右侧得到<=1的方法数(二分求出):2 + // 2 * 2 + // 都累加起来 + // 其实和课上讲的一样!多看一下例子 + long ans = 0; + long count = 1; + for (int i = 1; i < leftSize; i++) { + if (leftSum[i] != leftSum[i - 1]) { + ans += count * (long) find(w - leftSum[i - 1]); + count = 1; + } else { + count++; + } + } + ans += count * (long) find(w - leftSum[leftSize - 1]); + return ans; + } + + // 生成左部分的累加和,每一个累加和出来,都记录 + public static void dfsLeft(int cur, int end, long sum) { + if (cur == end) { // 已经终止位置了 + // 记录累加和 + leftSum[leftSize++] = sum; + } else { + // 可能性1,不要当前数 + dfsLeft(cur + 1, end, sum); + // 可能性2,要当前数 + dfsLeft(cur + 1, end, sum + arr[cur]); + } + } + + // 生成右部分的累加和,每一个累加和出来,都记录 + public static void dfsRight(int cur, int end, long sum) { + if (cur == end) { // 已经终止位置了 + // 记录累加和 + rightSum[rightSize++] = sum; + } else { + // 可能性1,不要当前数 + dfsRight(cur + 1, end, sum); + // 可能性2,要当前数 + dfsRight(cur + 1, end, sum + arr[cur]); + } + } + + // <= num的数的个数,返回 + public static int find(long num) { + int ans = -1; + int l = 0; + int r = rightSize - 1; + int m = 0; + while (l <= r) { + m = (l + r) / 2; + if (rightSum[m] <= num) { + ans = m; + l = m + 1; + } else { + r = m - 1; + } + } + return ans + 1; + } + +} \ No newline at end of file