题解:洛谷 P1957 口算练习题
【题目来源】
【题目描述】
王老师正在教简单算术运算。细心的王老师收集了 \(i\) 道学生经常做错的口算题,并且想整理编写成一份练习。编排这些题目是一件繁琐的事情,为此他想用计算机程序来提高工作效率。王老师希望尽量减少输入的工作量,比如 \(5+8\) 的算式最好只要输入 \(5\) 和 \(8\),输出的结果要尽量详细以方便后期排版的使用,比如对于上述输入进行处理后输出 \(5+8=13\) 以及该算式的总长度 \(6\)。王老师把这个光荣的任务交给你,请你帮他编程实现以上功能。
【输入】
第一行为数值 \(i\)
接着的 \(i\) 行为需要输入的算式,每行可能有三个数据或两个数据。
若该行为三个数据则第一个数据表示运算类型,\(a\) 表示加法运算,\(b\) 表示减法运算,\(c\) 表示乘法运算,接着的两个数据表示参加运算的运算数。
若该行为两个数据,则表示本题的运算类型与上一题的运算类型相同,而这两个数据为运算数。
【输出】
输出 \(2\times i\) 行。对于每个输入的算式,输出完整的运算式及结果,第二行输出该运算式的总长度
【输入样例】
4
a 64 46
275 125
c 11 99
b 46 64
【输出样例】
64+46=110
9
275+125=400
11
11*99=1089
10
46-64=-18
9
【核心思想】
-
问题分析:给定 \(i\) 行输入,每行可能是“操作符 + 两个数”(三个数据)或“两个数”(两个数据)。若为两个数据,则沿用上一行的操作符。需要根据操作符(
a加、b减、c乘)计算表达式,并输出完整的算式(如5+8=13)及其长度(字符数)。本质是字符串格式化与状态保持问题,核心在于处理变长输入并维护当前操作符。 -
算法选择:
- 字符串流 +
sprintf:使用stringstream将字符串转换为数字,用sprintf格式化输出算式。这是 C/C++ 中处理字符串格式化的常用方法。 - 状态维护:使用变量
flag存储当前操作符,若某行只有两个数据,则沿用flag。
- 字符串流 +
-
关键步骤:
- 读入:读取第一行整数 \(n\)(操作数)。
- 循环处理每行:
- 读入一个字符串
s。 - 判断
s是否为操作符("a"、"b"、"c"):- 若是,则更新
flag = s[0],并读入两个整数a, b。 - 若不是,则说明
s是第一个操作数,需要将其转换为整数a,并读入第二个整数b。
- 若是,则更新
- 根据
flag计算表达式,并使用sprintf生成算式字符串s2。 - 输出
s2和它的长度(strlen(s2))。
- 读入一个字符串
- 注意:使用
stringstream时,每次转换前需调用stream.clear()清空状态。
-
时间/空间复杂度:
- 时间复杂度:\(O(i \times L)\),其中 \(L\) 是算式字符串长度(常数),\(i\) 是行数。
- 空间复杂度:\(O(1)\),只使用了固定大小的字符数组。
-
字符串格式化与输入处理:
- 变长输入处理:通过判断读入的第一个 token 是字母还是数字,来决定是否更新操作符。这是处理“状态依赖型输入”的常用技巧。
sprintf的便利性:可以方便地按指定格式拼接字符串和数字,生成"a+b=c"形式的算式。- 字符串长度计算:
strlen(s2)返回字符数组的字符数(不含末尾的\0),正好是算式长度。 - 适用场景:这类“格式化输出 + 变长输入”的模拟题,常见于需要保持上下文中操作符状态的情况。
【算法标签】
普及- #字符串入门
【代码详解】
#include <bits/stdc++.h> // 包含标准库头文件(万能头文件)
using namespace std; // 使用标准命名空间
int main()
{
string s; // 定义字符串:存储输入的命令或数字
stringstream stream; // 定义字符串流:用于字符串和数字的转换
char s2[1000]; // 定义字符数组:存储格式化后的算式字符串
int n, a, b; // 定义变量:n-操作次数,a和b-操作数
char flag; // 定义变量:存储操作类型(a加/b减/c乘)
cin >> n; // 输入操作次数
// 处理每次操作
for (int i = 1; i <= n; i++)
{
cin >> s; // 输入命令或第一个数字
// 判断输入的是命令(a/b/c)还是数字
if (s[0] >= 'a' && s[0] <= 'c')
{
flag = s[0]; // 存储操作类型
cin >> a >> b; // 输入两个操作数
}
else
{
// 将字符串转换为数字
stream.clear(); // 清空流状态
stream << s; // 将字符串写入流
stream >> a; // 从流读取第一个数字
cin >> b; // 输入第二个数字
}
// 根据操作类型格式化算式字符串
if (flag == 'a')
{
sprintf(s2, "%d+%d=%d", a, b, a + b); // 加法算式
}
else if (flag == 'b')
{
sprintf(s2, "%d-%d=%d", a, b, a - b); // 减法算式
}
else
{
sprintf(s2, "%d*%d=%d", a, b, a * b); // 乘法算式
}
// 输出结果
cout << s2 << endl << strlen(s2) << endl; // 算式和算式长度
}
return 0; // 程序正常结束
}
【运行结果】
4
a 64 46
275 125
c 11 99
b 46 64
64+46=110
9
275+125=400
11
11*99=1089
10
46-64=-18
9
浙公网安备 33010602011771号