每个测试文件均包含多组测试数据。
第一行输入一个整数
,代表数据组数;
对于每组测试数据,输入如下:
第一行输入一个整数
,表示数组的长度;
第二行输入
个整数
,表示数组
的元素。
对于每组测试数据,新起一行。输出两个整数,用空格分隔:第一个整数为数组可以达到的最大总和;第二个整数为在达到最大总和的前提下初始最小的
。
2 2 3 3 3 1 2 3
6 0 9 3
import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 注意 hasNext 和 hasNextLine 的区别 int t = in.nextInt(); while (t-->0) { // 注意 while 处理多个 case int n = in.nextInt(); long[] num = new long[n]; long sum = 0; for(int i=0; i<n; i++){ num[i] = in.nextLong(); sum += num[i]; } // int[] flag = new int[30]; int max_j = 1; int min_j = 31; for(int i=0; i<n; i++){ long x = num[i]; int j = 0; while(x>0){ if(x%2==0) flag[j] = 1; //判断每个二进制位上是否存在0 x /= 2; j++; } max_j = max_j<j ? j : max_j; min_j = min_j>j ? j : min_j; // 高位补足 } // 用x去填每个位置上的0 long cur = 1; long x = 0; for(int i=0; i<max_j; i++){ if(i>=min_j || flag[i]==1) x+=cur; // [min_j,mat_j)范围内必然存在0需要x填充 cur *= 2; } sum += x; System.out.printf("%d %d\n", sum, x); } } }
/* When x is larger, sum() is also larger. => Find the smallest x in range [0, 0b1...1 where #1 == 0bmax(ai)'s 1s] => such that the sum() is at max Binary Search search range: x in [1, 0b1...1 where #1s == #0bmax(ai)'s digits] given that 0 <= ai < 2^30: #0bmax(ai)'s digits <= 30 search for what: First Occurrence of x such that sum() is at max assumption: as x goes up, sum() continues going up to a point and will no longer increase => Last Occurrence of x such that sum()_when_x > sum()_when_x-1 Complexity: TC: O(occurrence BS) * O(determine sum() for each x) = O(30) * O(n) ~ O(n) */ import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int numCases = in.nextInt(); for (int i = 0; i < numCases; i++) { int n = in.nextInt(); int[] arr = new int[n]; for (int j = 0; j < n; j++) { arr[j] = in.nextInt(); } Result result = smallestXLargestSum(arr); System.out.println(result.sum + " " + result.x); } } // Helpers /* Given an arr[], return the smallest x where 0bx has #digits <= 0blargest ai's #digits * such that sum(ai) is the largest. */ private static Result smallestXLargestSum(int[] arr) { int largestNumDigits = getLargestNumDigits(arr); int largestX = 1; for (int i = 1; i < largestNumDigits; i++) { // shifting & filling with 1 largestX <<= 1; largestX |= 1; } // System.out.println("largestX = " + largestX); // At this point, largestX = 0b1...1 (#1s == largestNumDigits) // initialize Occurrence BS int left = 1; int right = largestX; long prevSum = getSumWithX(0, arr); // sum() when x = 1 int midX = 0; // represent x while (left < right - 1) { midX = left + (right - left) / 2; long currSum = getSumWithX(midX, arr); if (currSum > prevSum) { // search to the right of mid (inclusive) left = midX; prevSum = currSum; } else { // prevSum >= currSum right = midX - 1; } } // post processing long sumWithRightX = getSumWithX(right, arr); if (right - 1 >= 0 && sumWithRightX > getSumWithX(right - 1, arr)) { return new Result(sumWithRightX, right); } long sumWithLeftX = getSumWithX(left, arr); if (left - 1 >= 0 && sumWithLeftX > getSumWithX(left - 1, arr)) { return new Result(sumWithLeftX, right); } else return new Result(getSumWithX(0, arr), 0); } // Given an x, return the sum() by applying the formulas. private static long getSumWithX(int x, int[] arr) { long sum = 0; for (int num: arr) { sum += num | x; x = num & x; } // System.out.println("When x = " + x + ", sum() = " + sum); return sum; } // return the #digits of binary form of the largest ai. Assert return number is in range 1 ~ 30 private static int getLargestNumDigits(int[] arr) { int max = arr[0]; for (int i = 1; i < arr.length; i++) { if (arr[i] > max) max = arr[i]; } int numDigits = 0; if (max == 0) return 1; while (max > 0) { numDigits++; max >>= 1; } // System.out.println("for current arr with length = " + arr.length + ", largestNumDigits = " + numDigits); return numDigits; } } class Result { long sum; int x; public Result(long sum, int x) { this.sum = sum; this.x = x; } }
public class MaxSumAndX { // 计算数字的二进制位数(0的位数为1) private static int getBitLength(int num) { if (num == 0) { return 1; } int bits = 0; while (num > 0) { bits++; num >>= 1; } return bits; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 输入数组(示例输入) System.out.println("请输入数组元素(以空格分隔):"); String[] parts = scanner.nextLine().split(" "); int[] a = new int[parts.length]; for (int i = 0; i < parts.length; i++) { a[i] = Integer.parseInt(parts[i]); } // 步骤1:计算初始总和S int S = 0; for (int num : a) { S += num; } // 步骤2:计算数组最大值及其二进制位数b int maxA = a[0]; for (int num : a) { if (num > maxA) { maxA = num; } } int b = getBitLength(maxA); // 步骤3:计算mask(第k位为1表示所有元素第k位都是1) int mask = 0; for (int k = 0; k < b; k++) { boolean allOne = true; for (int num : a) { if ((num >> k & 1) != 1) { // 第k位不是1 allOne = false; break; } } if (allOne) { mask |= 1 << k; // 第k位置为1 } } // 步骤4:构造最小x(包含所有可清除位) int x = 0; for (int k = 0; k < b; k++) { if ((mask >> k & 1) == 0) { // 第k位是可清除位 x |= 1 << k; } } // 最大总和 = S + x int maxSum = S + x; // 输出结果 System.out.println("最大总和:" + maxSum); System.out.println("对应的最小x:" + x); } }