洛谷 U140098 计数

洛谷传送门

题目背景

从古到今,人类的计数方式有着显著的进步。

追溯到五千年到八千年前,这时,四大文明古国都早已从母系社会过渡到父系社会了,生产力的发展导致国家雏形的产生,生产规模的扩大则刺激了人们对大数的需要。比如某个原始国家组织了一支部队,国王陛下总不能老是说:“我的这支战无不胜的部队共计有9名士兵!”于是,慢慢地就出现了“十”、“百”、“千”、“万”这些符号。在我国商代的甲骨文上就有“八日辛亥允戈伐二千六百五十六人”的刻文:即在八日辛亥那天消灭敌人共计2656人。在商周的青铜器上也刻有一些大的数字,以后又出现了“亿”、“兆”这样的大数单位。

而在古罗马,最大的记数单位只有“千”.他们用M表示一千.“三千”则写成“MMM”.“一万”就得写成“MMMMMMMMMM”。难以想象,如果他们需要记一千万时怎么办,难道要写上一万个M不成?

总之,人们为了寻找记大数的单位是花了不少脑筋的。旧社会在农村读私塾,一些私塾先生会教:“最大的数叫‘猴子翻跟斗’”。这位私塾先生可能认为孙悟空一个跟斗翻过去的路程是最最远的,不能再远了,所以完全可以用“猴子翻跟斗”来表示最大的数。在古印度,使用了一系列大数单位后,最后的最大的数的单位叫做“恒河沙”.是呀,恒河中的沙子谁数得清!

然而,古希腊有一位伟大的学者,他却数清了“充满宇宙的沙子数”,那就是阿基米德.他写了一篇论文,叫做《计沙法》。在这篇文章中,他提出的记数方法,同现代数学中表示大数的方法很类似。他从古希腊的最大数字单位“万”开始,引进新数“万万(亿)”作为第二阶单位,然后是“亿亿”(第三阶单位),“亿亿亿”(第四阶单位),等等,每阶单位都是它前一阶单位的1亿倍。阿基米德的同时代人、天文学家阿里斯塔克斯曾求出地球到天球面距离10,000,000,00010,000,000,000斯塔迪姆(11斯塔迪姆=188=188米)。这个距离当然比现在我们所认识的宇宙要小得多,这才仅仅是太阳到土星的距离。阿基米德假定这个“宇宙”里充满了沙子.然后开始计算这些沙子的数目。最后他写道:“显然,在阿里斯塔克斯计算出的天球里所能装入的沙子的粒数,不会超过一千万个第八阶单位”。如果要把这个沙子的数目写出来,就是10,000,000×(100,000,000)_710,000,000×(100,000,000)7或者就得在11后边写上6363个00:1,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,0001,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000。这个数,我们现在可以把它写得简单一些:即写成1×10^{63}1×1063。而这种简单的写法,据说是印度某个不知名的数学家发明的。这种用在11与1010间的一个数乘以1010的若干次幂的记数方法就是“科学记数法”。

用科学记数法表示数时,不改变数的符号,只是改变数的书写形式而已,可以方便的表示日常生活中遇到的一些极大或极小的数。

如:光的速度大约是300,000,000300,000,000米/秒;全世界人口数大约是:6,100,000,0006,100,000,000.

这样的数,读、写都很不方便,我们可以免去写这么多重复的00,将其表现为这样的形式:

6,100,000,000=6.1×10^96,100,000,000=6.1×109

或:

0.00001=1×10^{-5}0.00001=1×10−5

即绝对值小于1的数也可以用科学记数法表示为aa乘1010的负nn次方的形式。

题目描述

虽然科学记数法是小学四年级的数学知识。但是为了纪念出题人在CSP-S2020CSPS2020的考场上被坐在身旁的小学生反复敲打,现将科学记数法的记法向选手叙述。对于不同选手可能存在的对科学计数法的认知差别,皆以本叙述为准:

对于一个数xx

1、若|x|>1∣x∣>1,则记为a imes 10n*a*×10*n*的形式。n*n*的值由x*x*的位数决定,设m*m*为x*x*的位数,则n=m-1*n*=*m*−1,a=frac{x}{10n}a=10n**x

2、若|x|<1∣x∣<1,则n=-(m-m_1),a=x imes 10^{m-m_1}n=−(mm1),a=x×10mm1,其中mm为xx的位数,m_1m1为xx的有效数位。

与此同时,在计算数学中,数学家们引入了新的符号EE以代替这种1010的整数次幂的表示形式。具体地,有:

1、a imes 10^n=aEna×10n=aEn

2、特别地,当n=0n=0时,省略E0E0。

根据以上规律,编写程序,解决“给出一个合法的十进制数,求其科学记数法表示”这类问题是很容易的。我们当下面临的问题是:不保证给出的十进制数合法。具体地,有:

1、可能出现若干前置0。

2、可能出现若干后置0。

3、小数点可以单独出现而不需要前后缀。即:.612.612和914.914.这类数都是有可能出现的。

那么,现在给你一个长度为NN的、符合以上要求的数字,请你按以上要求编写程序,求出其正确的科学计数法表示。

输入格式

从文件count.incount.i**n中读入数据。

一行一个长度为NN的字符串,描述一个待转换的数字。

输出格式

输出到文件count.outcount.out中。

一行一个字符串,表示这个数字的合法科学计数法表示。


命题背景:

为了纪念CSP-S2020 T1挂分,特意出了这道题来训练选手的审题及对各种复杂数据的调试能力。

也就是从废话连篇的题面中提取关键信息。但是说实在的,这套题出的还是有些不好,因为前面的真的就是纯废话,中间一点有价值的东西都没有,所以不看也罢。

但是拿这玩意搞搞选手心态练练选手心理素质,并且练练码力,我觉得也是不错的啊。

所以还是有很大价值的。


题解:

解法不唯一,依照题意模拟即可。

加入了很多hack数据来细节。

可能标算都不太细节。但是标算切了。

所以数据以我的为准吧。

代码:

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e6+6;
char ori[maxn];
bool flag;
int main()
{
	scanf("%s",ori+1);
	int len=strlen(ori+1);
	int l=1,r=len;
	int ppos=0;
	if(len==1)
	{
		printf("%c
",ori[l]);
		return 0;
	}
	while(ori[l]=='0')
		l++;
	if(ori[r]=='.')
		r--;
	for(int i=l;i<=r;i++)
		if(ori[i]=='.')
		{
			ppos=i;
			flag=1;
			break;
		}
	if(ppos==len)
		flag=0;
	if(ppos==l)
	{
		l++;
		while(ori[r]=='0')
			r--;
		if(ori[r]=='.')
			r--;
		while(ori[l]=='0')
			l++;
		int cnt=0;
		while(cnt<=r-l)
		{
			if(cnt==1)
				printf(".");
			printf("%c",ori[l+cnt]);
			cnt++;
		}
		printf("E%d
",-(l-ppos));
		return 0;
	}
	else if(flag==1)
	{
		while(ori[r]=='0')
			r--;
		if(ori[r]=='.')
			r--;
		while(ori[r]=='0')
			r--;
		int cnt=0;
		while(cnt<=r-l)
		{
			if(cnt==1)
				printf(".");
			if(ori[l+cnt]=='.')
			{
				cnt++;
				continue;
			}
			printf("%c",ori[l+cnt]);
			cnt++;
		}
		if(ppos-l-1==0)
			return 0;
		printf("E%d
",ppos-l-1);
		return 0;
	}
	else if(flag==0)
	{
		if(l==r)
		{
			printf("%c",ori[l]);
			return 0;
		}
		int cnt=0;
		int zhi=r-l;
		while(ori[r]=='0')
			r--;
		while(cnt<=r-l)
		{
			if(cnt==1)
				printf(".");
			printf("%c",ori[l+cnt]);
			cnt++;
		}
		printf("E%d
",zhi);
		return 0;
	}
	return 0;
}