A、阶乘求和
【问题描述】
令 S= 1!+ 2!+ 3!+ ..+ 202320232023!,求 S 的末尾 9 位数字。
public class Main {
public static void main(String[] args) {
//计算阶乘的算法
long start = 1;
String s = "202320232023";
long end = Long.parseLong(s); // 将字符串转换为长整型数字
long sum = 0;
long cj = 1;
while (start <= end) {
cj *= start; // 计算当前数字的阶乘
cj %= 1000000000; // 取模 10^9,保留末尾 9 位数字
sum += cj; // 将当前阶乘加到总和中
sum %= 1000000000; // 取模 10^9,保留末尾 9 位数字
start++; // 移动到下一个数字
if (start > 40) // 如果当前数字大于 40,打印当前总和(调试用)
System.out.println(sum);
}
// 输出最终的末尾 9 位数字
System.out.println(sum);
}
}
B、幸运数字
【问题描述】
哈沙德数是指在某个固定的进位制当中,可以被各位数字之和整除的正整 数。例如 126 是十进制下的一个哈沙德数,因为(126)10 mod(1+2+6)=0;126 也是八进制下的哈沙德数,因为(126)10=(176)8,(126) 10 mod(1+7+ 6)=0;同时 126 也是16 进制下的哈沙德数,因为(126)10=(7 e)16,(126) 10 mod(7 +é)=0。小蓝认为,如果一个整数在二进制、八进制、十进制、十六进制下均为哈沙德数,那么这个数字就是幸运数字,第1至第10个幸运数字的十进制表示为:1,2,4,6,8,40,48,72,120,126...。现在他想知道第 2023个幸运数字是多少?你只需要告诉小蓝这个整数的十进制表示即可。
public class Main {
public static void main(String[] args) {
// 十进制转成其他进制
Integer.toBinaryString(int i)
Integer.toOctalString(int i)
Integer.toHexString(int i)
// 二进制转成十进制:
String binary = "1010";
int decimalFromBinary = Integer.parseInt(binary, 2);
int j = 0;
for (int i = 1; i < 10000000; i++) {
if (BaseConversion(i)) {
j++;
if (j == 2023) {
System.out.println(i);
break;
}
}
}
}
/**
* 检查一个数字是否满足条件:
* 该数字在十进制、二进制、八进制和十六进制下,都能被其各位数字之和整除。
*/
public static boolean BaseConversion(int n) {
// 十进制
int sum = 0; // 用于存储各位数字之和
int x = n; // 临时变量,用于计算
// 计算十进制下的各位数字之和
while (x != 0) {
sum += (x % 10); // 取出当前最低位的数字并加到 sum 中
x /= 10; // 去掉当前最低位
}
if (n % sum != 0) {
return false;
}
// 二进制
sum = 0; // 重置 sum
x = n; // 重置 x
// 计算二进制下的各位数字之和
while (x != 0) {
sum += (x % 2); // 取出当前最低位的数字并加到 sum 中
x /= 2; // 去掉当前最低位
}
if (n % sum != 0) {
return false;
}
// 八进制
sum = 0; // 重置 sum
x = n; // 重置 x
// 计算八进制下的各位数字之和
while (x != 0) {
sum += (x % 8); // 取出当前最低位的数字并加到 sum 中
x /= 8; // 去掉当前最低位
}
if (n % sum != 0) {
return false;
}
// 十六进制
int[] arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; // 十六进制数字映射
sum = 0; // 重置 sum
x = n; // 重置 x
// 计算十六进制下的各位数字之和
while (x != 0) {
sum += (arr[x % 16]); // 取出当前最低位的数字并加到 sum 中
x /= 16; // 去掉当前最低位
}
if (n % sum != 0) {
return false;
}
// 如果所有进制下都能被各位数字之和整除,返回 true
return true;
}
}
C:数组分割
【问题描述】
小蓝有一个长度为 N 的数组 A = [ A 0 , A 1 , . . . , A N − 1 ] 。现在小蓝想要从 A 对应的数组下标所构成的集合 I = { 0 , 1 , 2 , . . . , N − 1 } 中找出一个子集 R 1 ,那么 R 1在 I 中的补集为 R 2 。记 S 1 = ∑ r ∈ R 1 A r , S 2 = ∑ r ∈ R 2 A r,我们要求 S 1 和 S 2 均为 偶数,请问在这种情况下共有多少种不同的 R 1。当 R1 或 R 2 为空集时我们将 S 1 或 S 2 视为 0。
【输入格式】
第一行一个整数 T ,表示有 T 组数据。 接下来输入 T 组数据,每组数据包含两行:第一行一个整数 N ,表示数组 A 的长度;第二行输入 N 个整数从左至右依次为 A 0 , A 1 , . . . , A N − 1 ,相邻元素之 间用空格分隔。
【输出格式】
对于每组数据,输出一行,包含一个整数表示答案
D、矩形总面积
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int x1 = sc.nextInt(); // 第一个矩形左下角的 x 坐标
int y1 = sc.nextInt(); // 第一个矩形左下角的 y 坐标
int x2 = sc.nextInt(); // 第一个矩形右上角的 x 坐标
int y2 = sc.nextInt(); // 第一个矩形右上角的 y 坐标
int x3 = sc.nextInt(); // 第二个矩形左下角的 x 坐标
int y3 = sc.nextInt(); // 第二个矩形左下角的 y 坐标
int x4 = sc.nextInt(); // 第二个矩形右上角的 x 坐标
int y4 = sc.nextInt(); // 第二个矩形右上角的 y 坐标
// 计算第一个矩形的面积
long area1 = (long) (x2 - x1) * (y2 - y1);
// 计算第二个矩形的面积
long area2 = (long) (x4 - x3) * (y4 - y3);
// 计算重叠部分的宽度和高度
long l = Math.min(x2, x4) - Math.max(x1, x3);
long w = Math.min(y2, y4) - Math.max(y1, y3);
// 如果有重叠部分
long overlapArea = 0;
if (l >= 0 && w >= 0) {
overlapArea = l * w;
}
// 计算总面积
long totalArea = area1 + area2 - overlapArea;
// 输出总面积
System.out.println(totalArea);
}
}
E、蜗牛(时间限制: 1.0s 内存限制: 512.0MB)
【问题描述】
这天,一只蜗牛来到了二维坐标系的原点。 在 x 轴上长有 n 根竹竿。它们平行于 y 轴,底部纵坐标为 0 ,横坐标分别 为 x 1 , x 2 , ..., x n 。竹竿的高度均为无限高,宽度可忽略。蜗牛想要从原点走到第 n 个竹竿的底部也就是坐标 ( x n , 0) 。它只能在 x 轴上或者竹竿上爬行,在 x 轴
上爬行速度为 1 单位每秒;由于受到引力影响,蜗牛在竹竿上向上和向下爬行 的速度分别为 0 . 7 单位每秒和 1 . 3 单位每秒。 为了快速到达目的地,它施展了魔法,在第 i 和 i + 1 根竹竿之间建立了传 送门(0 < i < n ),如果蜗牛位于第 i 根竹竿的高度为 a i 的位置 ( x i , a i ) ,就可以 瞬间到达第 i + 1 根竹竿的高度为 b i +1 的位置 ( x i +1 , b i +1 ), 请计算蜗牛最少需要多少秒才能到达目的地。
【输入格式】
输入共 1 + n 行,第一行为一个正整数 n ;
第二行为 n 个正整数 x 1 , x 2 , . . . , x n ;
后面 n − 1 行,每行两个正整数 a i , b i +1 。
【输出格式】
输出共一行,一个浮点数表示答案( 四舍五入保留两位小数 )。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); // 竹竿数量
int[] x = new int[n]; // 竹竿横坐标
for (int i = 0; i < n; i++) {
x[i] = sc.nextInt();
}
// 动态规划数组,dp[i] 表示到达第 i 根竹竿底部的最小时间
double[] dp = new double[n];
dp[0] = x[0]; // 从原点到第一根竹竿的时间
// 读取每对竹竿之间的高度信息
int[] a = new int[n - 1];
int[] b = new int[n - 1];
for (int i = 0; i < n - 1; i++) {
a[i] = sc.nextInt();
b[i] = sc.nextInt();
}
// 动态规划计算最短时间
for (int i = 1; i < n; i++) {
// 不使用传送门的时间
dp[i] = dp[i - 1] + (x[i] - x[i - 1]);
// 使用传送门的时间
double timeWithTeleport = dp[i - 1] + a[i - 1] / 0.7 + (x[i] - x[i - 1]) + b[i] / 1.3;
dp[i] = Math.min(dp[i], timeWithTeleport);
}
// 输出总时间,四舍五入保留两位小数
System.out.printf("%.2f\n", dp[n - 1]);
}
}
F、合并区域
【问题描述】
小蓝在玩一款种地游戏。现在他被分配给了两块大小均为 N × N 的正方形 区域。这两块区域都按照 N × N 的规格进行了均等划分,划分成了若干块面积 相同的小区域,其中每块小区域要么是岩石,要么就是土壤,在垂直或者水平 方向上相邻的土壤可以组成一块土地。现在小蓝想要对这两块区域沿着边缘进 行合并,他想知道合并以后可以得到的最大的一块土地的面积是多少(土地的 面积就是土地中土壤小区域的块数)? 在进行合并时,小区域之间必须对齐。可以在两块方形区域的任何一条边 上进行合并,可以对两块方形区域进行 90 度、 180 度、 270 度、 360 度的旋转, 但不可以进行上下或左右翻转,并且两块方形区域不可以发生重叠。
【输入格式】
第一行一个整数 N 表示区域大小。 接下来 N 行表示第一块区域,每行 N 个值为 0 或 1 的整数,相邻的整数 之间用空格进行分隔。值为 0 表示这块小区域是岩石,值为 1 表示这块小区域 是土壤。 再接下来 N 行表示第二块区域,每行 N 个值为 0 或 1 的整数,相邻的整 数之间用空格进行分隔。值为 0 表示这块小区域是岩石,值为 1 表示这块小区 域是土壤。
【输出格式】
一个整数表示将两块区域合并之后可以产生的最大的土地面积。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 读取区域大小
int[][] region1 = new int[N][N];
int[][] region2 = new int[N][N];
// 读取第一块区域
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
region1[i][j] = sc.nextInt();
}
}
// 读取第二块区域
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
region2[i][j] = sc.nextInt();
}
}
// 计算每块区域的土地面积
int maxArea1 = calculateMaxLandArea(region1);
int maxArea2 = calculateMaxLandArea(region2);
// 合并区域并计算最大土地面积
int maxCombinedArea = 0;
for (int rotation = 0; rotation < 4; rotation++) {
int[][] rotatedRegion2 = rotateRegion(region2, rotation);
int combinedArea = calculateCombinedLandArea(region1, rotatedRegion2);
maxCombinedArea = Math.max(maxCombinedArea, combinedArea);
}
// 输出最大土地面积
System.out.println(maxCombinedArea);
}
/**
* 计算区域的最大土地面积
*/
private static int calculateMaxLandArea(int[][] region) {
int maxArea = 0;
boolean[][] visited = new boolean[region.length][region[0].length];
for (int i = 0; i < region.length; i++) {
for (int j = 0; j < region[0].length; j++) {
if (region[i][j] == 1 && !visited[i][j]) {
int area = dfs(region, visited, i, j);
maxArea = Math.max(maxArea, area);
}
}
}
return maxArea;
}
/**
* 深度优先搜索计算土地面积
*/
private static int dfs(int[][] region, boolean[][] visited, int i, int j) {
if (i < 0 || i >= region.length || j < 0 || j >= region[0].length || region[i][j] == 0 || visited[i][j]) {
return 0;
}
visited[i][j] = true;
int area = 1;
area += dfs(region, visited, i - 1, j);
area += dfs(region, visited, i + 1, j);
area += dfs(region, visited, i, j - 1);
area += dfs(region, visited, i, j + 1);
return area;
}
/**
* 旋转区域
*/
private static int[][] rotateRegion(int[][] region, int rotation) {
int N = region.length;
int[][] rotatedRegion = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
switch (rotation) {
case 0:
rotatedRegion[i][j] = region[i][j];
break;
case 1:
rotatedRegion[i][j] = region[N - 1 - j][i];
break;
case 2:
rotatedRegion[i][j] = region[N - 1 - i][N - 1 - j];
break;
case 3:
rotatedRegion[i][j] = region[j][N - 1 - i];
break;
}
}
}
return rotatedRegion;
}
/**
* 计算合并后的最大土地面积
*/
private static int calculateCombinedLandArea(int[][] region1, int[][] region2) {
int N = region1.length;
int maxArea = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (region1[i][j] == 1 && region2[i][j] == 1) {
int area = dfsCombined(region1, region2, i, j);
maxArea = Math.max(maxArea, area);
}
}
}
return maxArea;
}
/**
* 深度优先搜索计算合并后的土地面积
*/
private static int dfsCombined(int[][] region1, int[][] region2, int i, int j) {
if (i < 0 || i >= region1.length || j < 0 || j >= region1[0].length || region1[i][j] == 0 || region2[i][j] == 0) {
return 0;
}
region1[i][j] = 0;
region2[i][j] = 0;
int area = 1;
area += dfsCombined(region1, region2, i - 1, j);
area += dfsCombined(region1, region2, i + 1, j);
area += dfsCombined(region1, region2, i, j - 1);
area += dfsCombined(region1, region2, i, j + 1);
return area;
}
}
G、买二赠一
【问题描述】
某商场有 N 件商品,其中第 i 件的价格是 A i 。现在该商场正在进行 “ 买二 赠一” 的优惠活动,具体规则是: 每购买 2 件商品,假设其中较便宜的价格是 P (如果两件商品价格一样,
则 P 等于其中一件商品的价格),就可以从剩余商品中任选一件价格不超过 P /2 的商品,免费获得这一件商品。可以通过反复购买 2 件商品来获得多件免费商 品,但是每件商品只能被购买或免费获得一次。 小明想知道如果要拿下所有商品(包含购买和免费获得),至少要花费多少钱?
【输入格式】
第一行包含一个整数 N 。
第二行包含 N 个整数,代表 A 1 , A 2 , A 3 , . . . , A N
【输出格式】
输出一个整数,代表答案。
一种骗分写法:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt(); // 商品数量
int[] prices = new int[N]; // 商品价格
for (int i = 0; i < N; i++) {
prices[i] = sc.nextInt();
}
sc.close();
// 对商品价格进行排序
Arrays.sort(prices);
long totalCost = 0; // 总成本
int i = N - 1; // 从最贵的商品开始
// 模拟购买和免费获得的过程
while (i >= 0) {
if (i >= 2) {
// 购买两件商品
totalCost += prices[i] + prices[i - 1];
// 免费获得一件商品
i -= 3;
} else if (i == 1) {
// 购买两件商品
totalCost += prices[1] + prices[0];
i -= 2;
} else if (i == 0) {
// 只有一件商品,直接购买
totalCost += prices[0];
i -= 1;
}
}
// 输出总成本
System.out.println(totalCost);
}
}