1 条题解
-
0
思路
题意:每次给出两个以十进制文本形式书写的实数 ,文本可能带有无意义的前导零、尾部多余的零,也可能带小数部分,长度还可能超出
long long。判断二者在数学意义上是否相等,相等输出YES,否则NO。不能用数值类型比较
文本长度可能超过
long long,小数位数也没有上限,因此既不能直接转整数,也不能用double(会有精度误差)。正确做法是把文本规范化成唯一的标准形式,再逐字符比较。规范化规则
把字符串按小数点切成“整数部分”和“小数部分”:
- 整数部分:去掉前导零。如
000123与123表示同一个整数;若整串都是 0,规范化为"0"。 - 小数部分:去掉后导零。如
0.500与0.5相等,因为末尾的 0 不影响数值;若删空,规范化为"0"。 - 拼接成
整数部分 + "." + 小数部分作为标准形式。
标准形式之所以唯一,是因为:一个有限十进制实数的小数表示,在去掉整数部分的冗余前导零和分数部分的冗余后导零之后是唯一的(例如
007.500与7.5都规范化为7.5)。因此两个文本相等当且仅当标准形式完全相同。边界处理
- 没有小数点的整数,切分后小数部分为空串,
cut_e0会返回"0",于是15与15.000都规范化为15.0,比较结果正确; - 小数点前为空(如
.5),整数部分为空串,cut_f0返回"0",得到0.5,与0.50一致; - 全零文本无论多少位前导/后导零,都会收敛到
0.0。
复杂度
每组比较需要 时间(三次线性扫描),额外空间 。
代码
#include<bits/stdc++.h> #define int long long #define dd double #define str string #define el cout << '\n' #define re return #define ff first #define ss second #define pll pair<int,int> #define pdd pair<dd,dd> #define all(x) x.begin(),x.end() #define pb push_back using namespace std; // 以小数点把字符串切成整数部分和小数部分(没有小数点时小数部分为空串) pair<str, str> split_dot(str s){ bool dot = 0; str f = "",e = ""; for(char c:s){ if(c=='.'){ dot = 1; continue; } if(!dot){ f += c; }else{ e += c; } } return {f, e}; } // 去掉整数部分的前导零;全为 0(或为空)时返回 "0" str cut_f0(str s){ str ns = ""; bool n0 = 0; for(char c:s){ if(c !='0'){ n0 = 1; // 遇到第一个非零字符后才开始接收 } if(n0){ ns += c; } } return (ns.empty()? "0":ns); } // 去掉小数部分的后导零;全为 0(或为空)时返回 "0" str cut_e0(str s){ while (!s.empty() and s.back()=='0') { s.pop_back(); } return (s.empty()? "0":s); } void go(){ str a, b; cin>>a>>b; // 分别切分整数部分与小数部分 auto [fa, ea] = split_dot(a); auto [fb, eb] = split_dot(b); // 化为标准形式:整数去前导零 + "." + 小数去后导零 str sa = cut_f0(fa) + "." + cut_e0(ea); str sb = cut_f0(fb) + "." + cut_e0(eb); cout<< (sa==sb? "YES":"NO");el; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr); int _=1; cin >>_; // 读入比对次数 T while(_--){ go(); } return 0; } - 整数部分:去掉前导零。如
- 1
信息
- ID
- 46
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者