1 solutions
-
0
题面解释:塔子哥是一个喜欢数学的小学生,他在课余时间经常玩一些有趣的数学游戏。有一天,他收到了一个神秘的信件,信中写着一个包含阿拉伯数字、小数点和特殊字符的加法表达式。这些特殊字符包括
!
、@
和#
,并且它们之间的加法运算规则如下:! + ! = 0
、! + @ = 13
、! + # = 4
、@ + @ = 7
、@ + # = 20
和# + # = 5
。为了能够正确计算出这个表达式的结果并在三天内回信,塔子哥需要你的帮助。输入的第一行为一个整数len
,表示加法表达式的长度();第二行为一个长度为len
的字符串,表示加法表达式。输出一个整数或小数ans
,表示表达式的运算结果,输出结果应忽略前导零和后导零,并且当小数点后面为0时只需要输出整数部分。题解
这道题目要求我们模拟两个数的加法,其中数的形式包含阿拉伯数字、小数点及特殊字符(
!
、@
、#
)。由于这些特殊字符之间有特定的加法规则,我们需要根据这些规则进行处理。解决思路
- 解析输入:首先读取表达式长度和表达式字符串,找到加号
+
的位置,将表达式分为两个部分。 - 处理小数点:为了方便后续计算,我们确保两个数都有小数部分。如果没有小数部分,则在后面加上
.0
。 - 分离整数部分和小数部分:分别提取出整数部分和小数部分。
- 模拟加法:
- 小数部分加法:从小数部分开始逐位相加,并处理进位。
- 整数部分加法:同样逐位相加,注意进位。
- 格式化输出:在输出结果时,去掉不必要的前导零和后导零,并根据规则决定是否输出小数点后面的零。
代码分析
这段代码实现了对包含阿拉伯数字、小数点和特殊字符(
!
、@
、#
)的加法表达式的模拟加法运算。主要步骤包括:-
变量定义:使用了
n
来存储输入的表达式长度,s
用于存储加法表达式,t
用于追踪进位。 -
特殊字符加法规则:
get
函数处理特殊字符之间的加法运算,根据字符组合返回相应的结果。 -
小数部分加法:
suf_add
函数从小数部分逐位加法,调用get
函数处理特殊字符,并在计算过程中管理进位。 -
整数部分加法:
pre_add
函数与小数部分类似,从整数部分进行逐位加法,并在结束后处理剩余的进位。 -
主函数逻辑:主函数读取输入,查找加号并分割字符串,确保每部分都有小数点,最后调用相应的加法函数计算结果,并格式化输出,去除多余的零。
Python代码
_ = input() # 读取输入长度,实际未使用 a, b = input().split('+') # 读取加法表达式,分割成两个部分 a 和 b # 分割整数部分和小数部分 if '.' in a: a_int, a_dec = a.split('.') # 如果 a 中有小数点,分割为整数和小数部分 else: a_int, a_dec = a, '' # 如果没有小数点,小数部分为空 if '.' in b: b_int, b_dec = b.split('.') # 如果 b 中有小数点,分割为整数和小数部分 else: b_int, b_dec = b, '' # 如果没有小数点,小数部分为空 # 分别对齐整数部分和小数部分 if len(a_int) > len(b_int): # 如果 a 的整数部分较长,则在 b 的整数部分前补零 b_int = '0' * (len(a_int) - len(b_int)) + b_int else: # 如果 b 的整数部分较长,则在 a 的整数部分前补零 a_int = '0' * (len(b_int) - len(a_int)) + a_int # 对齐小数部分 if len(a_dec) > len(b_dec): # 如果 a 的小数部分较长,则在 b 的小数部分后补零 b_dec = b_dec + '0' * (len(a_dec) - len(b_dec)) else: # 如果 b 的小数部分较长,则在 a 的小数部分后补零 a_dec = a_dec + '0' * (len(b_dec) - len(a_dec)) # 定义一位的加法运算函数, carry为进位 def sym_add(x, y, carry): # 定义特殊字符的加法规则 rule = { '!!': 0, '!@': 13, '@!': 13, '!#': 4, '#!': 4, '@@': 7, '@#': 20, '#@': 20, '##': 5 } if x in '!@#': # 如果 x 是特殊字符 s = str(rule[x+y] + carry) # 根据规则计算加法结果 else: s = str(int(x) + int(y) + carry) # 否则直接进行数字加法 # 如果结果只有一位,返回结果和进位0 if len(s) == 1: return s, 0 else: return s[1], int(s[0]) # 否则返回当前位和进位 # 计算小数部分 ans, carry = '', 0 # 初始化结果和进位 for i in reversed(range(len(a_dec))): # 从小数部分的最后一位开始计算 res, carry = sym_add(a_dec[i], b_dec[i], carry) # 进行加法运算 ans = res + ans # 结果前插入当前位 # 添加小数点 ans = '.' + ans # 在结果前添加小数点 # 计算整数部分 for i in reversed(range(len(a_int))): # 从整数部分的最后一位开始计算 res, carry = sym_add(a_int[i], b_int[i], carry) # 进行加法运算 ans = res + ans # 结果前插入当前位 if carry != 0: # 如果最后还有进位,添加到结果前面 ans = str(carry) + ans # 去除前导0和后导0 ans = ans.strip('0') # 去除结果中的前导0 # 有可能整数部分只有0, 去除前导0后就没有整数部分了, 因此要补一个0 if ans[0] == '.': # 如果结果以小数点开头 ans = '0' + ans # 在前面补零 # 如果没有小数部分, 那么小数点也应该去掉 if ans[-1] == '.': # 如果结果以小数点结尾 ans = ans[:-1] # 去掉小数点 print(ans) # 输出最终结果
Java
import java.util.ArrayList; import java.util.Scanner; public class Main { public static ArrayList<Character> A = new ArrayList<>(), B = new ArrayList<>(), res = new ArrayList<>(); public static ArrayList<Character> A1 = new ArrayList<>(), B1 = new ArrayList<>(), res1 = new ArrayList<>(); static int flag = 0; public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); String s = in.next(); String[] split = s.split("\\+"); String a = split[0]; String b = split[1]; if(a.contains(".") && b.contains(".")){ String[] sa = a.split("\\."); String[] sb = b.split("\\."); String s1 = sa[1].length() >= sb[1].length() ? sa[1] : sb[1]; String s2 = sa[1].length() >= sb[1].length() ? sb[1] : sa[1]; int x = s1.length()-s2.length(); for(int i=1;i<=x;i++){ s2 = s2 + "0"; } for (int i = s1.length()-1; i >= 0; i--){ A1.add(s1.charAt(i)); B1.add(s2.charAt(i)); } add1(); s1 = sa[0].length() >= sb[0].length() ? sa[0] : sb[0]; s2 = sa[0].length() >= sb[0].length() ? sb[0] : sa[0]; //这里就是反着装进list for (int i = s1.length()-1; i >= 0; i--) A.add(s1.charAt(i)); for (int i = s2.length()-1; i >= 0; i--) B.add(s2.charAt(i)); add(); }else if(a.contains(".")){ String[] sa = a.split("\\."); String s1 = sa[0].length() >= b.length() ? sa[0] : b; String s2 = sa[0].length() >= b.length() ? b : sa[0]; //这里就是反着装进list for (int i = s1.length()-1; i >= 0; i--) A.add(s1.charAt(i)); for (int i = s2.length()-1; i >= 0; i--) B.add(s2.charAt(i)); add(); for (int i = sa[1].length()-1; i >=0; i--) { res1.add(sa[1].charAt(i)); } }else if(b.contains(".")){ String[] sa = b.split("\\."); String s1 = sa[0].length() >= a.length() ? sa[0] : a; String s2 = sa[0].length() >= a.length() ? a : sa[0]; //这里就是反着装进list for (int i = s1.length()-1; i >= 0; i--) A.add(s1.charAt(i)); for (int i = s2.length()-1; i >= 0; i--) B.add(s2.charAt(i)); add(); for (int i = sa[1].length()-1; i >=0; i--) { res1.add(sa[1].charAt(i)); } }else{ for (int i = a.length()-1; i >= 0; i--) A.add(a.charAt(i)); for (int i = b.length()-1; i >= 0; i--) B.add(b.charAt(i)); add(); } // 先算小数 StringBuilder string = new StringBuilder(); //因为是反着装进list的,输出就得从末尾开始输出,例如751->157 // for (int i = res.size()-1; i>=0; i--) System.out.print(res.get(i)); // System.out.print("."); // for (int i = res1.size()-1; i>=0; i--) System.out.print(res1.get(i)); for (int i = res.size()-1; i>=0; i--){ string.append(res.get(i)); } string.append('.'); for (int i = res1.size()-1; i>=0; i--){ string.append(res1.get(i)); } while(string.charAt(string.length()-1)=='0'){ string.deleteCharAt(string.length()-1); } if(string.charAt(string.length()-1)=='.') string.deleteCharAt(string.length()-1); while(string.charAt(0)=='0'&&string.length()>1){ string.deleteCharAt(0); } System.out.println(string.toString()); } //这里就是最基础的十进制加法,将A和B的当前位加在一起,需要进位就靠t/=10来判断进位 public static void add() { //如果之前一位进位了,那么t就是1,没进位t就是0 int t = flag; for (int i = 0; i < B.size(); i++) { char num1 = A.get(i); char num2 = B.get(i); if(num1>='0'&&num1<='9'&&num2>='0'&&num2<='9')t+=num2-'0'+num1-'0'; else if(num1=='!'&&num2=='!')t=t; else if(num1=='!'&&num2=='@'||num1=='@'&&num2=='!')t+=13; else if(num1=='!'&&num2=='#'||num1=='#'&&num2=='!')t+=4; else if(num1=='@'&&num2=='#'||num1=='#'&&num2=='@')t+=20; else if(num1=='@'&&num2=='@')t+=7; else if(num1=='#'&&num2=='#')t+=5; res.add( (char)((t % 10) + '0') ); t /= 10; } for (int i = B.size(); i < A.size(); i++) { int num= A.get(i); t = num - '0' + t; res.add((char)((t % 10) + '0')); t /= 10; } //特判,如果a和b长度一样且a的最高位加b的最高位进位的话,t还保留着进位信息,加到res就好 if (t > 0) res.add((char)(t+'0')); } public static void add1() { //如果之前一位进位了,那么t就是1,没进位t就是0 int t = 0; for (int i = 0; i < A1.size(); i++) { char num1 = A1.get(i); char num2 = B1.get(i); if(num1>='0'&&num1<='9'&&num2>='0'&&num2<='9')t+=num2-'0'+num1-'0'; else if(num1=='!'&&num2=='!')t=t; else if(num1=='!'&&num2=='@'||num1=='@'&&num2=='!')t+=13; else if(num1=='!'&&num2=='#'||num1=='#'&&num2=='!')t+=4; else if(num1=='@'&&num2=='#'||num1=='#'&&num2=='@')t+=20; else if(num1=='@'&&num2=='@')t+=7; else if(num1=='#'&&num2=='#')t+=5; res1.add((char)((t % 10) + '0') ); t /= 10; } //特判,如果a和b长度一样且a的最高位加b的最高位进位的话,t还保留着进位信息,加到res就好 if (t > 0) flag = t; } }
Cpp
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #define x first #define y second using namespace std; typedef long long ll; typedef pair<int, int> pii; const int N = 1010; int n; // 表达式的长度 string s; // 存储输入的加法表达式 int t = 0; // 全局变量,记录进位 // 处理特殊字符的加法运算 int get(char a, char b) { if (a == '!' && b == '!') return 0; else if (a == '!' && b == '@') return 13; else if (a == '!' && b == '#') return 4; else if (a == '@' && b == '@') return 7; else if (a == '@' && b == '#') return 20; else if (a == '#' && b == '#') return 5; return get(b, a); // 如果找不到规则,调换字符顺序 } // 小数部分加法 string suf_add(string a, string b) { string res = ""; // 存储结果 for (int i = max(a.size(), b.size()) - 1; ~i; i--) { char c = '0', d = '0'; // 默认字符为'0' if (i < (int)a.size()) c = a[i]; // 取出当前位 if (i < (int)b.size()) d = b[i]; // 取出当前位 // 判断是否是特殊字符并进行加法计算 if (!isdigit(c) && !isdigit(d)) t += get(c, d); else t += c - '0' + d - '0'; // 阿拉伯数字相加 res += to_string(t % 10); // 结果的当前位 t /= 10; // 更新进位 } reverse(res.begin(), res.end()); // 反转结果 while (res.size() > 1 && res.back() == '0') res.pop_back(); // 去除末尾零 return res; } // 整数部分加法 string pre_add(string a, string b) { reverse(a.begin(), a.end()); // 反转字符串以便从低位开始加 reverse(b.begin(), b.end()); string res = ""; for (int i = 0; i < (int)a.size() || i < (int)b.size(); i++) { char c = '0', d = '0'; if (i < (int)a.size()) c = a[i]; // 取出当前位 if (i < (int)b.size()) d = b[i]; // 取出当前位 // 判断是否是特殊字符并进行加法计算 if (!isdigit(c) && !isdigit(d)) t += get(c, d); else t += c - '0' + d - '0'; res += to_string(t % 10); // 结果的当前位 t /= 10; // 更新进位 } // 处理最后的进位 while (t) { res += to_string(t % 10); t /= 10; } while (res.size() > 1 && res.back() == '0') res.pop_back(); // 去除末尾零 reverse(res.begin(), res.end()); // 反转回原来的顺序 return res; } int main() { cin >> n >> s; // 输入长度和表达式 int pos = s.find('+'); // 查找加号的位置 string a = s.substr(0, pos), b = s.substr(pos + 1); // 分割成两部分 if (a.find('.') == a.npos) a += ".0"; // 若没有小数点,加上.0 if (b.find('.') == b.npos) b += ".0"; // 若没有小数点,加上.0 int pos_a = a.find('.'), pos_b = b.find('.'); // 找到小数点的位置 string pre_a = a.substr(0, pos_a), suf_a = a.substr(pos_a + 1); // 分离整数和小数部分 string pre_b = b.substr(0, pos_b), suf_b = b.substr(pos_b + 1); // 先计算小数部分,再计算整数部分 string suf_res = suf_add(suf_a, suf_b); string pre_res = pre_add(pre_a, pre_b); // 输出结果 cout << pre_res; if (suf_res != "0") cout << '.' << suf_res; // 如果小数部分不为零,则输出 return 0; }
- 解析输入:首先读取表达式长度和表达式字符串,找到加号
- 1
Information
- ID
- 19
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 6
- Tags
- # Submissions
- 189
- Accepted
- 23
- Uploaded By