笔试题一(小红的数组构造)
样例1:
注意,使用C++和Java的同学要用
long
而不是int
,防止计算结果过大而爆内存。因为在一些情况下,特别是当输入的
n
和k
值很大时,计算出的数组元素之和可能会超出int
类型的范围。为了避免溢出或内存不足的问题,应该使用更大的数据类型来存储和计算结果。在 Java 中,我们可以使用long
类型来代替int
,因为long
的取值范围比int
大得多。注意什么时候需要 采用long!
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
//输入两个正整数n和k
long n = sc.nextLong();
long k = sc.nextLong();
long sum = 0;
for(long i = 0; i <= n;i ++){
sum += i * k;
}
System.out.println(sum);
}
}
方法二:构造[k, 2k, 3k, ..., nk]
这样的数组即为符合要求的数组(这个结论很容易用反证法证明),使用等差数列求和公式可知该数组的和为
k + 2k + 3k + ... + nk = (1 + 2 + 3 + ... + n) * k = (1 + n) * n // 2 * k
故对于输入的两个参数n
和k
,只需要输出(1 + n) * n * k // 2
即为答案。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
long n = scanner.nextLong();
long k = scanner.nextLong();
System.out.println((1 + n) * n * k / 2);
scanner.close();
}
}
笔试题一(精华帖子)
思路
由于输出是最多的精华帖子数量,所以运营同学截取的这段长度为 k 的区间的左端点一定是某个精华区间的左端点。所以我们可以考虑遍历每个精华区间的左端点。对于每个左端点,找到此时截取长度 k 后能覆盖到的最右边的那个区间,再计算其中的精华帖子数量即可,计算时可用前缀和算法。另外,在每次遍历左端点时,为了提高效率,我们可以采用二分查找算法来寻找最右的那个区间。
import java.util.Arrays;
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n, m, k;
n = scanner.nextInt();
m = scanner.nextInt();
k = scanner.nextInt();
// 存储精华帖子区间
int[][] goodPost = new int[m][2];
for (int i = 0; i < m; i++) {
goodPost[i][0] = scanner.nextInt();
goodPost[i][1] = scanner.nextInt();
}
// 由于要使用二分查找,所以需要排序精华帖子区间
Arrays.sort(goodPost, (a, b) -> a[0] - b[0]);
// 前缀和,preSum[i] 表示从第 1 个区间到第 i 个区间(包含 1 和 i)的精华帖子的数量
int[] preSum = new int[m + 1];
for (int i = 1; i <= m; i++) {
preSum[i] = preSum[i - 1] + goodPost[i - 1][1] - goodPost[i - 1][0];
}
int maxNum = 0;
// 遍历每一个左端点
for (int i = 0; i < m; i++) {
// 长度为 k 的覆盖区间的右端点
int end = goodPost[i][0] + k;
int left = i, right = m - 1;
while (left <= right) {
int mid = (left + right) >> 1;
if (goodPost[mid][0] <= end) {
// mid 这个区间的左端点小于覆盖区间的右端点,此时有两种情况
// 1、mid 区间的右端点 >= end
// 2、mid 区间的右端点 < end
// 用 Math.min() 函数取两者最小值,统一处理
maxNum = Math.max(maxNum, preSum[mid] - preSum[i] + Math.min(end, goodPost[mid][1]) - goodPost[mid][0]);
left = mid + 1;
} else {
right = mid - 1;
}
}
}
System.out.println(maxNum);
}
}