从一题多解看解题方法
http://www.mydrs.org 6/16/2001 大榕树
信息学竞赛,要求学生有很强的思维能力和逻辑推理能力。下面通过一题多解,层层深入,希望能够起到抛砖引玉的作用。题目:求1×2×3×……×n所得的数末尾有多少个0?(1000〈n〈10000)即:若把n!分解成b×10 x形式,其中b为不能被10整除的正整数,求x为多少? 看到这个题目,一般读者想到计算机的运算速度那么快,可以先求出1×2×3×...×n这个数,再数出后面的0的个数,可是计算机的长整型也只能表示出10位有效数字,而n的阶乘(1000〈n〈10000)有上万位数,计算机能表示出来吗?所以这种方法行不通,我们必须想出其它的方法来解决这个问题,在这里我们用PASCAL语言提供三种方法。 方法一:采用从1乘到n,每乘一个数判断一次,若后面有0则去掉后面的0,并记下去掉的0的个数。我们是求后面的0的个数,与前面一些数无关,为了不超出数的表示范围,去掉前面与0无关的数,只保留三位有效数,当乘完n次后就得到0的个数。 program ex1; var i,ii,n:integer; sum:longint; begin ii:=0; sum:=1; write('please input n:'); readln(n); for i:=1 to n do begin sum:=sum*i; while sum mod 10=0 do begin sum:=sum div 10; ii:=ii+1; end; sum:=sum mod 1000; end; writeln(ii:6); end. 方法二:第一种方法能得到正确的结果,可是运行的次数太多了,在1×2×3×...×n这些数中有些与生成0无关的数(如3、7、9、13等)可以不考虑进去,其实影响生成0的数只有2的倍数和5的倍数,如在1到9这些数中只有2×5,4×5,6×5,8×5,这些数能生成0,从这些数中我们还可以看出,真正影响生成0的是5的倍数,这些数的分解数含2的数显然多于含5的数,因此我们可以得出这样一个结论:n!的分解数中有多少个5,末尾就有多少个0。这样就可以使外面的大循环的次数减少五分之四。 program ex2; var i,ii,j,n:integer; begin j:=5;ii:=0; write('please input n:'); readln(n); while j<=n do begin i:=j; while i mod 5 =0 do begin i:=i div 5; ii:=ii+1; end; j:=j+5; end; writeln(ii:6); end. 方法三:第二种方法是把含5的数转变成含0的数,再求0的个数,我们已经知道n!的分解数中有多少个5就有多少个0,我们可不可以直接求5的个数呢?答案是肯定的。这种方法就是根据含5的个数求0的个数,用层层剥皮法。先以5为步长,执行一次循环,进行第一次剥皮,求出含5的个数(个数为n/5取整),通过第一次剥皮5,10,15,20,25,30...变成1,2,3,4,5,6...再以5 2为步长,执行第二次循环,进行第二次剥皮,求出含5 2的个数(个数为n/25取整),在第一次剥皮后25,50,75,100,125,150……这些数变成5,10,15,20,25,30……再经过第二次剥皮就变成1,2,3,4,5,6……再以5 3为步长……直到步长大于或等于n退出循环,具体实现如下: program ex3; var i,ii,n:integer; begin write('please input n:'); readln(n); i:=n; ii:=0; while i>=5 do begin i:=i div 5 ; ii:=ii+i; end; writeln(ii:6); end. 这三种方法,从常规思维到方法一,从方法一到方法三,思维过程步步加深,循环次数成倍减少,方法一与方法二外循环次数分别为n次和n/5次,里面还有内循环,方法三只需√n次循环,笔者实习期间曾以此题为竞赛题目考查学生的思维能力,推理能力,激发学生学习计算机的兴趣,起到了很好的效果。
|