题目大意:
给定两个位数不超过100的非负浮点数,如果保留n位有效数字的情况下写成0.@@@@*10^@的形式,如果两者相同,则输出YES和该数字,如果不同输出NO并且分别输出2个数。
算法思路:
仔细思考下,这种形式和科学技术法很相似但是有不同于科学计数法,因为前面一定得是0.开头,那么输入的数字的形式按照道理来说只有一种,那就是$abcd.efg$,但是在这里仔细分成2类,一类就是$0.efg$ 的形式,一类就是$abcd.@@@$ 的形式(好像和没说一样,哈哈哈),这里把第一类分出来是因为在处理第二类的时候会出现$abcd$全部是0的情况(这是一个陷阱),这样就退化到了第一类,然后就是输入的数字有可能本来就是第一类,这样方便代码解耦(个人观点),接下来就具体说这2类数字的处理方法.
第一类$0.efg$
首选我们知道最后一定是0.开头,所以使用string r="0."
保存最后结果,这类数字分为2种情况,一种就是小数点后面全是0,这种情况下就直接让r后面添加n个0和10^0
即可(这也是一个陷阱),另外一种就是小数点后面有不为0的数字,那么用index保存其位置,让r添加原字符串的index到最后位置的子串,注意如果该子串的长度s.size()-index<n
,则得在后面补充0,使得其小数点后面的有效位为n(这也是一个陷阱),然后再添加指数部分,指数的次幂pos+1-index
(index-pos-1
就是小数点到不为0之间0的个数,相反数就是指数部分) 。最后返回r即可。该类数字使用type1
函数处理。
第二类$abcd.@@@$(包含整数)
这类数字也分为2种情况,第一种情况就是小数点前面全部是0,这样的数字(比如0000.@@@,等效于0.@@@)等价于第一类数字,直接将小数点前面的一个0到最后位置截断,然后调用type1
处理即可,第二种情况就是小数点前面有不为0的数字,这样我们用index保存小数点前面不为0的数字的位置,同样的让r初始化为"0."然后再移除小数点(移到前面去了),将index后面n位子字符串拼接到r的后面,如果该子字符串的长度s.size()-index<n
,要在后面补0,最后再添加指数部分,指数的次幂为pos-index
(pos-index为小数点前面不为0数字的个数,也就是小数点移动的位数)
注意点:
1、数字签名可能会有前导0,比如000 000.12 00004522145.155,测试点2,4,6考察,处理方法可以采取去除前导0,这里是直接归类于第二类,然后会跳转到第一类,直接处理小数点后面的数字即可。
2、对于000.00的情况需要输出0.@@@(n个@)*10^0,测试点6考察。
3、对于整数的处理,这里采用在最后添加一个小数点归纳在第二类中。
4、对于本身不需要移动小数点的情况,除了000.00这样的需要在最后添加10^0外,其他的点没有考察,也就是像0.12保留2位数字输出0.12和0.12*10^0都是可以的。
提交结果:
测试数据:
4 0000 0000.00 //YES 0.0000$*$10^0
4 00123.5678 0001235 //NO 0.1235$*$10^3 0.1235$*$10^4
3 0.0520 0.0521 // NO 0.520$*$10^-1 0.521$*$10^-1
4 00000.000000123 0.0000001230 // YES 0.1230$*$10^-6
4 00100.00000012 100.00000013 // YES 0.1000$*$10^3
5 0010.013 10.012 // NO 0.10013$*$10^2 0.10012$*$10^2
4 123.5678 123.5 // YES 0.1235$*$10^3
3 123.5678 123 // YES 0.123$*$10^3
4 123.0678 123 // YES 0.1230$*$10^3
3 0.000 0 // YES 0.000$*$10^0
AC代码:
#include<cstdio>
#include<string>
using namespace std;
string type1(string s,int n,int pos){//处理形式0.*****的字符串
string r = "0.";//保存最后结果
int index;//保存小数点后面第一个不为0的位置
for(index=pos+1;index<s.size();++index){
if(s[index]!='0') break;
}
if(index==s.size()){//说明小数点后面全部为0(或者小数点后面没有了,比如输入了0),取有效长度的0,然后添加10^0即可
for(int i=0;i<n;++i){//最后一个测试点考查的就是这一点
r += "0";
}
r += "*10^0";
}else{//存在不为0的数字,那么该数字后面n位为有效位,不够补0
r += s.substr(index,n);
if(s.size()-index<n){//说明有效位长度不够,得补0
for(int i=0;i<n-(s.size()-index);++i){
r += "0";
}
}
r += "*10^"+to_string(pos+1-index);//index-pos-1就是小数点到不为0之间0的个数,相反数就是指数部分
}
return r;
}
string type2(string s,int n,int pos){//处理形式abcd.*****
int index;//保存小数点前面第一个不为0的位置
string r;//保存最后结果
for(index=0;index<pos;++index){
if(s[index]!='0') break;
}
if(index==pos){//小数点前面全部是0,从小数点后面找,转化为type1类型
s = s.substr(pos-1);//截取0.*****部分
r = type1(s,n,1);//pos位置就是1
}else{//小数点前面有不为0的部分
r += "0.";
s.erase(s.begin()+pos);//移除小数点
r += s.substr(index,n);//截取index后面n为字符串,不够补0
if(s.size()-index<n){//有效位不够,补0
for(int i=0;i<n-(s.size()-index);++i){
r += "0";
}
}
r += "*10^"+to_string(pos-index);//添加指数部分
}
return r;
}
string process(string s,int n){//将当前数字写成0.*****的形式并且保留n位
if(s.find(".")==string::npos){//当前字符串没有小数点是整数
s += ".";//在最后添加小数点
}
int pos = s.find(".");//获得小数点的下标
string r;//保留最终结果
if(pos==1&&s[0]=='0'){//该数字本来就是0.****的形式
r = type1(s,n,pos);
} else{//abcd.****的形式
r = type2(s,n,pos);
}
return r;
}
int main(){
int n;
string s1,s2;
char t1[101],t2[101];
scanf("%d %s %s",&n,t1,t2);
s1 = t1;
s2 = t2;
s1 = process(s1,n);
s2 = process(s2,n);
if(s1==s2){
printf("YES %s",s1.c_str());
}else{
printf("NO %s %s",s1.c_str(),s2.c_str());
}
return 0;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。