嗨,大家好,这是我的第二篇博文,欢迎来踩
,留在你们的小脚印呀!
正如大家所知,在C语言中整型变量用4个字节表示,表示范围略大于2乘以10的9次方,而长整型用8位表示,表示范围略小于2乘以10
的19次方。如果所要计算的数字或者计算的中间变量超过整型表示范围,则会出现错误结果,所以应该想办法避免这种错误的发生。
现在我们来看两个简单的例子:
A)输入n,计算S=1!+2!+3!+4!+。。。+n!的末6位(不含前导0)。n<=10的6次方。这里,n!表示前n个正整数之积。
样例输入:10
样例输出:37913
分析:如果按照以前的思路,先依次求算阶乘,再相加求和,再求除以1000000的余数,显然不可行。因为1000!早已超出长整型的表示范围,所以计算机是无法帮你表示出1000000!数值的,需要再次审题,找到突破口。发现,题目让我们求算末6位,对于加法、减法、乘法的整数表达式除以正整数n
的余数,可以在每步计算之后对n取余,结果不变。这就是我们要用到的有利条件。
基于这个思路,可以写出正确的编程代码如下:
#include
#include
int main(){
const int MOD=1000000;
int i,j,n,S=0,f;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
f=1;
for(j=1;j<=i;j++){
f=f*j%MOD;
}
S=(S+f)%MOD;
}
printf("%d\n",S);
printf("Time used=%.2lf\n",(double)clock()/CLOCKS_PER_SEC);
return 0;
}
通过多测输入测试,我们可以发现一个问题,当输入数字大于等于25的时候,输出结果都是一样的820313,仔细分析的朋友可能已经知道原因了,前25个数字相乘的结果有6个0,所以再对1000000取余没有影响,结果相同。
B)输入不超过1000的正整数n,输出n!=1*2*3*4*.....*n的精确结果。
分析:细读题目,发现这道题好像没有上道题那么有突破点,显然中间结果会溢出,这该如何解决?换个思路,我们第一次学习乘法的时候是怎么做算术题的?对,列竖式,这道题可以模拟小学生算术题那样列算式求解。
用一个足够大的数组来存放要输出的结果,各元素初始化为0,只有第一个元素初始化为1,因为从1开始相乘。
这里f[0]表示个位,f[1]表示十位,f[2]表示百位,f[3]表示千位,依次递增一个数量级。
源代码如下:
#include
#include
const int
maxn=3000;//注意估计1000!大约等于4*10的2567次方,所以用3000个数组长度预存结果
int f[maxn];
int main(){
int i,j,n;
scanf("%d",&n);
memset(f,0,sizeof(f));
f[0]=1;
for(i=1;i<=n;i++)
{
int c=0;int sum=0;
for(j=0;j
{
sum=i*f[j]+c;
f[j]=sum;
c=sum/10;
}
}
for(j=maxn-1;j>=0;j--){
if(f[j])break;
}
for(i=j;i>=0;i--){
printf("%d",f[i]);
}
return 0;
}
不信的朋友可以试一试:输入30
输出265252859812191058636308480000000
这是长整型无法表示的整数,我们却让计算机帮我“手算”出来了,够朋友!
今天就写到这里,下周再见!