- 豆芽内训(1)
芝麻开门~
- @ 2026-2-26 15:30:01
- 先搞清楚单位之间的换算关系(记 “换算倍数表”) 长度单位(大→小): km → m:×1000;km → mm:×1000000;m → mm:×1000 重量单位(大→小): kg → g:×1000;kg → mg:×1000000;g → mg:×1000
- 拆解输入的信息(从题目里 “抠” 关键数据) 输入的每一行格式是:数字 单位1 = ? 单位2,比如1 km = ? mm,我们需要: 提取数字(比如 1) 提取单位 1(比如 km)、单位 2(比如 mm) 找到这两个单位对应的换算倍数(比如 km→mm 是 ×1000000)
- 计算 + 按格式输出 用提取的数字 × 换算倍数,再把结果填回原来的格式里(把?换成答案)。 二、完整 C++ 代码(带详细注释,适合幼儿芽小朋友)
// 引入C语言标准输入输出库,用于scanf/printf等输入输出操作
#include <cstdio>
// 引入C语言标准库(本题未用到,可保留)
#include <cstdlib>
// 引入C语言字符串处理库,用于strlen/字符串比较等操作
#include <cstring>
// 引入算法库(本题未用到,可保留)
#include <algorithm>
// 使用标准命名空间,避免写std::前缀
using namespace std;
// 核心函数:根据单位字符串,返回该单位对应的“基准值”(用于换算)
// 参数s:传入的单位字符串(如"km"、"m"、"mm"、"kg"等)
int get_base(char *s) {
// 第一步:判断单位字符串长度是否为1(比如"m"/"g"/"mm"?不,mm长度是2,m长度是1)
if (strlen(s) == 1) {
// 长度为1的单位(m/g),基准值设为1000
return 1000;
}
// 长度不为1时:判断首字符是否是'k'(km/kg),是则基准值1000000,否则1(mm/mg)
return s[0] == 'k' ? 1000000 : 1;
}
// 主函数:程序入口
int main() {
// T:题目数量(测试用例数)
int T;
// 读取题目数量
scanf("%d", &T);
// 循环处理每一道题目,T--表示每处理1题,T减1,直到T为0
while(T --) {
// x:需要转换的数字(如1、100等)
int x;
// s1:原单位字符串(如km),s2:目标单位字符串(如mm),数组长度5足够存单位(最多3个字符+结束符)
char s1[5], s2[5];
// 读取转换的数字x(如1)
scanf("%d", &x);
// 读取原单位s1(如km)
scanf("%s", s1);
// 关键:跳过输入中的"= ? "这三个部分(因为输入格式是"x 单位1 = ? 单位2")
// 第一次scanf("%s", s2)读入"=",第二次读入"?",第三次读入目标单位s2(如mm)
scanf("%s", s2), scanf("%s", s2), scanf("%s", s2);
// 输出结果:按"x 单位1 = 换算后数字 单位2"格式打印
// 换算逻辑:x * 原单位基准值 / 目标单位基准值(核心换算公式)
printf("%d %s = %d %s\n", x, s1, x * get_base(s1)/get_base(s2), s2);
}
// 程序正常结束,返回0
return 0;
}
三、代码关键部分解释(幼儿芽小朋友能懂) 头文件: #include :用来输入输出(读题目、写答案) #include :用来处理 “km”“mm” 这些文字(字符串) getMultiple 函数: 专门负责 “查换算倍数”,比如输入km和mm,就返回 1000000 用if-else判断单位组合,像查 “乘法口诀表” 一样简单 main 函数(核心流程): cin >> N:读有几道题目 cin.ignore():小细节,避免读空行(小朋友可以先记住这个操作) for循环:一道一道处理题目,循环 N 次 sscanf:从输入的字符串里 “抠” 出数字和两个单位(比如从 “1 km = ? mm” 里抠出 1、km、mm) answer = num * multiple:计算最终结果,用long long是怕数字太大(比如 1000×1000000=1000000000,普通 int 装不下) cout:按要求输出,把?换成答案,其他字不变 四、测试样例演示 输入样例 1: plaintext 2 1 km = ? mm 1 m = ? mm 执行过程: 读 N=2,处理第一行: 抠出 num=1,unit1=km,unit2=mm 查倍数:km→mm=1000000 计算:1×1000000=1000000 输出:1 km = 1000000 mm 处理第二行: 抠出 num=1,unit1=m,unit2=mm 查倍数:m→mm=1000 计算:1×1000=1000 输出:1 m = 1000 mm 总结 核心逻辑:拆输入→查倍数→算结果→按格式输出,像做数学应用题一样分步走; 关键细节:用long long存储结果,避免数字太大 “装不下”; 代码特点:注释详细、逻辑简单,符合小朋友的编程认知,没有复杂语法。
我们要帮小杨完成数字替换的任务,核心思路就像给序列里的每个数字 “分类处理”,分三步就能搞定:
- 先找两个关键值(序列的最大值、最小值) 就像先找出一堆数字里 “最大的那个数” 和 “最小的那个数”,比如序列[-2, -1, 0, 1, 2]的最大值是 2,最小值是 - 2。
- 给每个数字 “判类别、做替换” 遍历序列里的每一个数字,按规则处理: 如果数字 大于 k → 换成第一步找到的最大值; 如果数字 小于 k → 换成第一步找到的最小值; 如果数字 等于 k → 保持不变。
- 输出替换后的完整序列 把处理后的数字按顺序打印出来就行啦。 二、完整 C++ 代码(带详细注释,适合幼儿芽小朋友) cpp
#include <iostream>
#include <vector>
#include <climits> // 用来获取整数的最大/最小值(INT_MAX、INT_MIN)
using namespace std;
int main() {
// 步骤1:读取输入的n(序列长度)和k(判断阈值)
int n, k;
cin >> n >> k;
// 步骤2:读取序列,并先找出序列的最大值和最小值
vector<int> nums(n); // 用vector存储序列,方便操作
int max_num = INT_MIN; // 初始化最大值为“最小的整数”,确保能被更新
int min_num = INT_MAX; // 初始化最小值为“最大的整数”,确保能被更新
for (int i = 0; i < n; i++) {
cin >> nums[i];
// 更新最大值:如果当前数字比max_num大,就替换
if (nums[i] > max_num) {
max_num = nums[i];
}
// 更新最小值:如果当前数字比min_num小,就替换
if (nums[i] < min_num) {
min_num = nums[i];
}
}
// 步骤3:遍历序列,按规则替换每个数字
for (int i = 0; i < n; i++) {
if (nums[i] > k) {
nums[i] = max_num; // 大于k → 替换为最大值
} else if (nums[i] < k) {
nums[i] = min_num; // 小于k → 替换为最小值
}
// 等于k的情况,保持不变,不用处理
}
// 步骤4:输出替换后的序列(空格分隔)
for (int i = 0; i < n; i++) {
cout << nums[i];
// 最后一个数字后面不加空格,其他加空格(符合输出规范)
if (i != n - 1) {
cout << " ";
}
}
return 0;
}
三、代码关键部分解释(小朋友能懂) 头文件说明: #include :负责输入(读数字)和输出(打印结果); #include :相当于 “变长数组”,用来存序列里的数字,比普通数组更灵活; #include :提供INT_MIN(最小整数)和INT_MAX(最大整数),方便初始化最大值 / 最小值。 找最大值 / 最小值的逻辑: 先把max_num设成 “最小的整数”,这样序列里第一个数字肯定比它大,能顺利更新; 遍历每个数字时,逐个比较:如果当前数字更大,就把max_num换成这个数;找最小值同理。 示例:序列[-2,-1,0,1,2],遍历后max_num=2,min_num=-2。 替换数字的逻辑: 再遍历一次序列,对每个数字做判断: 比如数字1(大于 k=0)→ 换成最大值2; 比如数字-1(小于 k=0)→ 换成最小值-2; 数字0(等于 k)→ 保持不变。 输出细节: 打印时,除了最后一个数字,其他数字后面加空格,避免末尾多一个空格(符合编程题的输出规范)。 四、测试样例演示 输入样例 1: plaintext 5 0 -2 -1 0 1 2 执行过程: 读 n=5,k=0;读序列[-2,-1,0,1,2]; 找最大值 / 最小值:max_num=2,min_num=-2; 替换每个数字: -2 < 0 → 替换为-2; -1 < 0 → 替换为-2; 0 = 0 → 保持0; 1 > 0 → 替换为2; 2 > 0 → 替换为2; 输出:-2 -2 0 2 2(和样例输出一致)。 五、进阶小提示(适配大数据量) 题目里说n≤10^5(最多 10 万个数字),我们的代码用vector存储、两次遍历(找最值 + 替换),时间复杂度是O(n),完全能处理这么大的数据量,不会超时~ 总结 核心逻辑:先找最值 → 逐个替换 → 规范输出,三步逻辑清晰,像做手工一样简单; 关键细节:初始化最值时用INT_MIN/INT_MAX,确保能正确找到序列的最值; 代码特点:注释详细、无复杂语法,符合小朋友的认知,同时适配题目大数据量的要求。
一、思维分析(小朋友易懂版) 我们要帮小杨做一个 “外星语言翻译器”,核心思路就像查英语字典翻译句子一样,分四步走:
- 先 “建字典”(存储 A 语言→B 语言的对应关系) 把输入的 N 组单词对应关系存起来,比如 A 语言的abc对应 B 语言的a,A 语言的d对应 B 语言的def,就像把单词和翻译抄在小本本上,方便后面查。
- 拆分原文(把文章拆成 “单词” 和 “标点”) 原文里的单词和标点混在一起(比如abc.d.d.abc.abcd.),我们要逐个字符扫描: 遇到小写字母:拼起来组成 “单词”; 遇到标点:先处理之前拼好的单词(查字典翻译),再把标点直接保留,然后重置 “单词” 为空,继续扫描。
- 查字典翻译单词 对每个拼好的 A 语言单词: 如果在字典里能找到 → 换成对应的 B 语言单词; 如果找不到 → 换成大写的UNK。
- 拼接结果 把翻译后的单词和保留的标点按原来的顺序拼起来,就是最终的翻译结果啦。 二、完整 C++ 代码(带详细注释,适合小朋友) cpp 运行
// 引入万能头文件,包含所有常用的C++库(iostream、string、map等),不用逐个引入
#include <bits/stdc++.h>
// 使用标准命名空间,避免写std::前缀(比如std::string→string)
using namespace std;
// 宏定义:把int替换为long long,防止数字溢出(本题单词长度短,实际用不到,但保留原代码风格)
#define int long long
// 定义常量N(本题未用到,保留原代码风格)
const int N = 1e4 + 5;
// 全局变量声明:
int n; // n:字典的条目数量
map<string, string> m; // 字典容器(键:A语言单词,值:B语言翻译),像查字典一样通过单词找翻译
string s, ans; // s:需要翻译的原文;ans:最终翻译结果
// 主函数(signed main等价于int main,适配long long的宏定义)
signed main() {
// 第一步:读取字典条目数量n
cin>>n;
// 第二步:循环读取n组单词对应关系,存入字典m
for(int i = 1; i <= n; i++) {
string a, b; // a:A语言单词,b:对应的B语言翻译
cin>>a>>b; // 读取一组A-B单词对
m[a] = b; // 存入字典:键是A单词,值是B单词(比如m["abc"] = "a")
}
// 第三步:读取需要翻译的原文字符串s
cin>>s;
// 核心技巧:在原文末尾加一个标点(.),确保最后一个单词能被处理
// 比如原文是"abc"(无结尾标点),加.后变成"abc.",遍历到.时会处理最后的abc
s += '.';
// 第四步:遍历原文,拆分单词+翻译+拼接结果
string t = ""; // 临时变量:存储正在拼接的A语言单词(比如逐个字符拼"abc")
for(char c : s) { // 逐个字符遍历原文的每个字符
// 情况1:当前字符是小写字母(属于A语言单词的一部分)
if(c >= 'a' && c <= 'z') {
t += c; // 把字母拼到临时单词t里(比如c='a'→t="a",c='b'→t="ab")
}
// 情况2:当前字符是标点(分割单词的符号)
else {
// 先处理已经拼好的临时单词t(如果t不为空)
if(t != "") {
// 查字典:如果t在字典中存在(m.count(t)返回1)
if(m.count(t)) {
ans += m[t]; // 把对应的B语言翻译加到结果里
}
// 字典中没有该单词
else {
ans += "UNK"; // 用大写UNK替换
}
t = ""; // 清空临时单词t,准备拼接下一个单词
}
// 标点直接保留到结果里(比如.、,等,和原文一致)
ans += c;
}
// 调试代码(注释掉):打印当前字符、结果、临时单词,方便看执行过程
// cout<<c<<" "<<ans<<" "<<t<<endl;
}
// 第五步:删除最后添加的那个.(因为之前手动加了一个,原文没有)
ans.pop_back();
// 第六步:输出最终的翻译结果
cout<<ans<<endl;
return 0; // 程序正常结束
}
三、代码关键部分解释(小朋友能懂) 核心工具:unordered_map(字典) 就像我们的英语单词本,dict["abc"] = "a" 表示把 “A 语言 abc” 和 “B 语言 a” 绑定; 查单词时用dict.find(单词),能找到就返回对应翻译,找不到就用UNK。 isPunctuation 函数(判断标点) 把题目里所有标点列成一个字符串,逐个对比当前字符是不是标点; 比如字符是.,就返回true,表示是标点;字符是a,返回false,表示是字母。 扫描文章的逻辑 遍历每个字符:字母就拼单词,标点就先翻译已拼的单词,再保留标点; 比如扫描abc.d时: 先拼abc → 遇到.,查字典换成a,再把.加到结果; 再拼d → 遍历结束后处理,查字典换成def。 处理结尾单词 如果文章最后是单词(比如abc),没有标点,循环结束后要单独处理这个单词,避免漏掉。 四、测试样例演示(用题目示例) 输入样例(正确示例,修正之前的错误样例): plaintext 2 abc a d def abc.d.d.abc.abcd. 执行过程: 建字典:dict["abc"]="a",dict["d"]="def"; 扫描文章abc.d.d.abc.abcd.: 拼abc → 遇到.,翻译为a,结果变成a.; 拼d → 遇到.,翻译为def,结果变成a.def.; 拼d → 遇到.,翻译为def,结果变成a.def.def.; 拼abc → 遇到.,翻译为a,结果变成a.def.def.a.; 拼abcd → 遇到.,查不到字典,翻译为UNK,结果变成a.def.def.a.UNK.; 输出结果:a.def.def.a.UNK.(和题目示例一致)。 总结 核心逻辑:建字典→拆文章→查字典翻译→拼结果,和查纸质字典翻译句子的逻辑完全一致; 关键细节: 用unordered_map快速查单词,比逐个对比快很多; 单独处理标点和结尾单词,避免漏译; 代码特点:注释详细、逻辑简单,没有复杂语法,适合小朋友理解和运行,同时满足题目所有输入输出要求。