csu22级c语言期中出线概率

问题 Q: 出线概率(10分)
[命题人 : 外部导入]
时间限制 : 1.000 sec 内存限制 : 128 MB

题目描述

2022世界杯正在火热进行中,小南是足球球迷,想知道某个球队的出线概率。经过严肃认真的研究,他发现其出线概率是一种可以计算的玄学:根据球队的名字可以得到出线概率!球队的名字由n(1≤n≤30)个小写字母c1, c2, …, cn组成,小写字母只包括’a’‘i’,其编号分别对应19,则出线概率的计算公式为:
(-1)1 (c1对应的编号) * 101 +(-1)2(c2对应的编号)102 + … (-1)n(cn对应的编号)*10n )/10n+1
最终结果保留到小数点后n位。例如当球队名字为fff时,f字母对应的编号是6,则出线概率为:(-60+600-6000)/10000=-0.546。
给定某个球队的名字,请你帮助小南计算一下该球队出现在下次世界杯的概率吧!注意有些球队的名字组成很长哦,最大可达30位呢。

输入

多个样例。每个样例输入1行包含一个由小写字母组成的字符串(小写字母只包括’a’~‘i’),表示球队的名字,长度为n(1≤n≤30)。

输出

每个样例输出一个实数表示出线概率,保留到小数点后n位。

样例输入 Copy
fff
aaaa
样例输出 Copy

没时间可以直接点击终版及终版优化看思路

思路

初看

这可太简单了,题说啥干啥。嘎嘎敲。‘‘保留到小数点后n位”,直接利用转换说明%nd补充n。成功答案错误。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[31];
	while (~scanf("%s", arr))
	{
		int n = 0;
		n=strlen(arr);
		int xiang = 1, gailv=0,jia=1;
		for (int i = 0; i <= n - 1; i++)
		{
			xiang *= (-1) * 10;
			jia = xiang*(arr[i] - 'a' + 1);
			gailv += jia;
		}
		printf("%.nd\n", gailv);//不能这样搞转换说明。
		//gailv忘记除最后一项10的n减1次方。处处是bug。。。。
	}
	return 0;
}

再看

浮点数精度是会丢失的。那么既然如此,先略去要除去10的n减1次方,搞出整数。先输出-0.或者0.,然后计算出需要补足的0。将计算出前面
(-1)1 (c1对应的编号) * 101 +(-1)2(c2对应的编号)102 + … (-1)n(cn对应的编号)*10n )这一串。负数用强制类型转换为正数。

int wei(int b)
{
	int bb = b; int n = 0;
	while (bb)
	{
		bb /= 10;
		n++;
	}
	return n;
}
#include<stdio.h>
#include<string.h>
int main()
{
	char arr[31];
	while (~scanf("%s", arr))
	{
		int n = 0;
		n = strlen(arr);
		int xiang = 1, gailv = 0, jia = 1;
		for (int i = 0; i <= n - 1; i++)
		{
			xiang *= (-1) * 10;
			jia = xiang * (arr[i] - 'a' + 1);
			gailv += jia;
		}
		while (gailv % 10 == 0)
		{
			gailv /= 10;
		}
		if (gailv < 0)
		{
			printf("-0.");
			for (int i = 1; i <= n - wei(gailv); i++)
				printf("0");
			printf("%u\n", (unsigned)gailv);//强转失败。
			//谁教的这样想当然的转。。。。。。
		}
		else
		{
			printf("0.");
			for (int i = 1; i <= n - wei(gailv); i++)
				printf("0");
			printf("%d\n", gailv);
		}
	}
	return 0;
}

为啥不对,因为对强制转换概念不清楚。-3转换为unsigned难道是3吗。当然不是。-3在计算机中的补码是4294967293的二进制形式。即为2的三十二次方4294967296(十进制)减去3等于4294967293。以无符号整型读写当然不对咯。

#include<stdio.h>
int main(void)
{
	int a = -2;
	int b = (unsigned)a;//b=-2;
	unsigned m= (unsigned)a; //m=4294967294
	printf("%u\n", -3);//4294967293
	printf("%o", -3);//37777777775(八进制)=十进制的4294967293
	return 0;
}

再再看

那么当是负数的时候,直接加负号把负数变成正数。这下题目中的样例对了。但是oj依旧不通过,注意有些球队的名字组成很长哦,最大可达30位呢。 定睛一看,原来。。。。。这用long long都不行。何况是int。。。。折腾这么久前面全是错误的轨道。看对题目很重要只能数组出马了一个个输出数字。

终版

(-1)1 (c1对应的编号) * 101 +(-1)2(c2对应的编号)102 + … (-1)n(cn对应的编号)*10n )/10n+1化简分式上下全部同除10;
根据题意,要填满数组的n位。如何填满呢。先观察题目,由于序号是1到9,那么(-1)1 (c1对应的编号) * 100 这一项一定比后一项(-1)2(c2对应的编号)*101 要小,(-1)1 (c1对应的编号) * 100 +(-1)2(c2对应的编号)*101 )一定是一个正数,我们利用加法结合律,先加第一项和第二项,第三项和第四项,第五项和第六项等。那么正好对应的每两项和的前两位都对应要求数组的两位(由于1到9,所以不会产生进位的问题,正好对应)。
如果这个n是奇数呢。前面的都两两配对,最后剩下的第n位加上前面的所有位,岂不是会把数组扰乱。那么我们进行人为的运算。例如aaa,-1+10-100=9-100=-(100-9)=-91,那么最后一位就是10减9等于1,前一位9减0等于9。由于第一项和第二项不可能是0,第一项加第二项末尾一定是有数字的,而不是0,所以第一项加第二项,第三项加第四项等等和的末尾一位一定是有数字的,而第n位的末尾是0,所以一定会借一位。而第n位一定是1或2或3或4或5等后面加上n减1个零,被借位后引起一系列推塔式反应。最后一位10减原来对应的数字,而前面的数字都要用9减去,最高位减1.

include<stdio.h>
#include<string.h>
int main()
{
	char arr[31]; int shuchu[31] = { 0 };
	while (~scanf("%s", arr))
	{
		int n = 0;
		n = strlen(arr);
		int xiang = 1, gailv = 0, jia = 1;
		for (int i = 1; i <= n-1 ; i+=2)
		{
				shuchu[n-i] = ((arr[i] - 'a' + 1) * 10 - (arr[i-1] - 'a' + 1))%10;
				shuchu[n-i - 1] = ((arr[i] - 'a' + 1) * 10 - (arr[i-1] - 'a' + 1)) /10; 
			
		}
		if (n % 2 == 1)
		{
		被借位后引起一系列推塔式反应。最后一位10减原来对应的数字,而前面的数字都要用9减去,最高位减1.
			shuchu[0] = (arr[n-1] - 'a' +1-1);//最高位减1
			printf("-0.%d",shuchu[0]);
			for (int i = 1; i < n - 1; i++)
			{
				printf("%d", 9-shuchu[i]);//而前面的数字都要用9减去.
			}
			printf("%d", 10 - shuchu[n - 1]);//最后一位10减原来对应的数字
		}
		else
		{
			printf("0.");
			for (int i = 0; i <= n - 1; i++)
			{
				printf("%d", shuchu[i]);
			}
		}
		printf("\n");
	}
	return 0;
}

总结

当遇到数字特别长的时候要警惕,要用数组或者字符串等解决问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值