前言:考点技巧讲解 + 竞赛题实战
1.取位数
例如:123456
需求:取前三位和后三位
解:123456 / 1000 = 123
123456 % 1000 = 456
工具一:取余 (% 10) —— “取尾”
规则: 一个数 % 10 的结果,永远是这个数的个位数(最右边的一位)。
-
479 % 10 结果是 9
-
47 % 10 结果是 7
-
4 % 10 结果是 4
-
12345 % 10 结果是 5
以此类推,想取后两位用%100,取后三位用%1000......
工具二:整除 (/ 10) —— “去尾”
规则: 一个整数 / 10 的结果,永远是这个数去掉个位数后剩下的部分。
-
479 / 10 结果是 47 (小数点后的部分被丢弃了)
-
47 / 10 结果是 4
-
4 / 10 结果是 0
-
12345 / 10 结果是 1234
以此类推,想取前几位,就可以用/10、/100......的方法将后几位剔除掉
思考:取位数的方法有很多,为什么要用数学方法来取?
1. 极致的性能(速度飞快)
% 和 / 是 CPU 的原生指令,是计算机硬件层面直接支持的运算。执行这些操作几乎不花费任何时间。
2. 极低的内存消耗
数学方法只使用了几个 int 变量,这些变量存储在一种叫做“栈”的高速内存区域中。而字符串方法创建了对象,这些对象存储在“堆”内存中,需要更复杂的内存管理(包括后续的垃圾回收)。简单说,数学方法几乎不占用额外内存。
3. 通用性
无论你用 Java, C++, Python, JavaScript 还是任何主流编程语言,整数的取余和整除运算逻辑都是完全一样的。这是一个放之四海而皆准的计算机科学基础知识。学会了它,你就在所有语言中都掌握了处理数字位数的最佳方法。
考点竞赛题
问题描述
借书高峰期,人来人往,图书馆内的自动借书机前排起了长队。小蓝正在排队时突然被告知,需要快速确认自己借书卡编号是否有效。
自动借书机规定,每张借书卡编号都必须是 66 位数,为了简化检查,工作人员采用了这样的规则:借书卡编号的前三位数字之和必须等于后三位数字之和。若不满 66 位,自动在前面补零。
例如编号
45123
,补零后为045123
:前三位数字为
0
、4
、5
,和为 0+4+5=9;后三位数字为1
、2
、3
,和为 1+2+3=6;两边和不相等,编号无效。
现在,给出小蓝的借书卡编号 NN,请你帮忙判断这个编号是否有效。
输入格式
输入一行,包含一个整数 NN,满足 0≤N<1060≤N<106。
输出格式
输出一行,如果编号有效,打印
YES
;否则打印NO
。样例输入
123321
样例输出
YES
样例输入 2
23456
样例输出 2
NO
题解:
import java.util.Scanner;
public class Main3 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
scan.close();
// 1. 将N地分为两部分
int firstPart = N / 1000; // 对于45123,这里得到45
int lastPart = N % 1000; // 对于45123,这里得到123
// 2. 分别计算各位之和,整数除法会自动处理“补零”
int sumFirst = (firstPart / 100) + ((firstPart / 10) % 10) + (firstPart % 10);
int sumLast = (lastPart / 100) + ((lastPart / 10) % 10) + (lastPart % 10);
if (sumFirst == sumLast) {
System.out.print("YES");
} else {
System.out.print("NO");
}
}
}
2.在两个数的和固定的条件下,如何组合这两个数,才能让它们的乘积取到最大值?
例如: 将数字10分成两个正整数。
需求: 如何分配这两个数,才能让它们的乘积最大?
解(实验法):
组合方式 (a, b) | 两数之和 (a+b) | 两数之积 (a*b) |
(1, 9) | 10 | 1 * 9 = 9 |
(2, 8) | 10 | 2 * 8 = 16 |
(3, 7) | 10 | 3 * 7 = 21 |
(4, 6) | 10 | 4 * 6 = 24 |
(5, 5) | 10 | 5 * 5 = 25 (最大) |
结论: 当两个数的和固定时,这两个数的值越接近(最理想是完全相等),它们的乘积就越大。
策略:“均分策略” 算法
规则: 将一个总量 N 分成尽可能相等的两部分 a 和 b。
-
a = N / 2 (利用整数除法自动向下取整的特性)
-
b = N - a (剩下的部分)
例如:
-
N = 100: a = 50, b = 100 - 50 = 50。
-
N = 99: a = 49, b = 99 - 49 = 50。
思考:为什么要掌握这个数学模式?
1.识别问题本质
很多竞赛题目(如切蛋糕、分配资源、安排任务)都是伪装。这个模式能帮助你迅速剥开故事外壳,看穿其“和定积最大”的数学内核。能识别出模式,问题就解决了一大半。
2.效率的巨大提升 (从 O(N) 到 O(1))
- 暴力解法: 用一个 for 循环,尝试所有可能的组合(从 (0, N) 到 (N, 0)),找出最大值。时间复杂度是 O(N)。
- 数学优化解法: 直接运用“均分策略” (a = N/2; b = N-a;),一步到位算出最优组合。时间复杂度是 O(1)。
考点竞赛题
问题描述
为了即将到来的蓝桥派对,小蓝准备了一个巨大的矩形蛋糕。他想把这个蛋糕切成尽可能多的块,以便分给更多的朋友。
小蓝手头有一把长刀,他总共可以切 NN 刀。他的切法有如下规则:
- 每一刀要么是“横切”(平行于蛋糕的某两条边),要么是“竖切”(与横切垂直)。
- 每一刀都必须笔直地从蛋糕的一条边切到其相对的另一条边。
现在,小蓝想知道,如何合理地分配这 NN 刀(即决定多少刀用于横切,多少刀用于竖切),才能使得最终得到的蛋糕块数量最多?请你帮助他计算出这个最大数量。
输入格式
输入的第一行包含一个整数 NN(1≤N≤1041≤N≤104),表示小蓝可以切的总刀数。
输出格式
输出一个整数,表示能够切出的最大蛋糕块数量。
样例输入
2
样例输出
4
题解:
import java.util.Scanner;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int count = scan.nextInt();
int h = count / 2;
int s = count - h;
int cake = (h + 1) * (s + 1);
System.out.print(cake);
scan.close();
}
}
未完待续......(OS:每日一更)