ImageVerifierCode 换一换
格式:DOCX , 页数:31 ,大小:30.80KB ,
资源ID:20118730      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/20118730.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(C语言程序设计漫谈之从n末尾有多少个0谈起.docx)为本站会员(b****1)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

C语言程序设计漫谈之从n末尾有多少个0谈起.docx

1、C语言程序设计漫谈之从n末尾有多少个0谈起从“n!末尾有多少个0”谈起 在学习循环控制结构的时候,我们经常会看到这样一道例题或习题。问n!末尾有多少个0?POJ 1401就是这样的一道题。【例1】Factorial (POJ 1401)。DescriptionThe most important part of a GSM network is so called Base Transceiver Station (BTS). These transceivers form the areas called cells (this term gave the name to the cellu

2、lar phone) and every phone connects to the BTS with the strongest signal (in a little simplified view). Of course, BTSes need some attention and technicians need to check their function periodically.ACM technicians faced a very interesting problem recently. Given a set of BTSes to visit, they needed

3、 to find the shortest path to visit all of the given points and return back to the central company building. Programmers have spent several months studying this problem but with no results. They were unable to find the solution fast enough. After a long time, one of the programmers found this proble

4、m in a conference article. Unfortunately, he found that the problem is so called Travelling Salesman Problem and it is very hard to solve. If we have N BTSes to be visited, we can visit them in any order, giving us N! possibilities to examine. The function expressing that number is called factorial

5、and can be computed as a product 1.2.3.4.N. The number is very high even for a relatively small N.The programmers understood they had no chance to solve the problem. But because they have already received the research grant from the government, they needed to continue with their studies and produce

6、at least some results. So they started to study behaviour of the factorial function.For example, they defined the function Z. For any positive integer N, Z(N) is the number of zeros at the end of the decimal form of number N!. They noticed that this function never decreases. If we have two numbers N

7、1 N2, then Z(N1) = Z(N2). It is because we can never lose any trailing zero by multiplying by any positive number. We can only get new and new zeros. The function Z is very interesting, so we need a computer program that can determine its value efficiently.InputThere is a single positive integer T o

8、n the first line of input. It stands for the number of numbers to follow. Then there is T lines, each containing exactly one positive integer number N, 1 = N = 1000000000.OutputFor every number N, output a single line containing the single non-negative integer Z(N).Sample Input6360100102423456873537

9、3Sample Output0142425358612183837(1)编程思路1。 n!是一个很大的数,不能将其求出后,再统计其末尾0的个数。由于10=2*5,且n!中因子2的个数一定超过因子5的个数。一个很容易想到的办法是:对于1、2、3、n中的每一个数i求5的因子个数,然后将所有5的因子个数加起来就是n!中末尾0的个数。 如何求一个数x含有的5的因子个数呢?可以写成一个简单的循环。 cnt=0; while (x%5=0) cnt+; / x能被5整除,含有一个因子5,计数 x=x/5; / 商有可能还含有因子5 这样,一个容易想到的解决办法的程序可写成一个二重循环,外循环控制从1n,表

10、示参与n!计算的每个数,内循环对每个数,求其含有5的因子个数。(2)源程序1-1。#include int main() int t,n,cnt,i,x; scanf(%d,&t); while(t-) scanf(%d,&n); cnt=0; for (i=1;i=n;i+) x=i; while (x%5=0) cnt+; x/=5; printf(%dn,cnt); return 0;这个源程序可以正确运行,但将其提交给 POJ 1401 “Factorial” 时,评测系统给出的结论是:Time Limit Exceeded。超时了,说明程序的效率不高。有些同学想到,源程序中外循环 f

11、or (i=1;i=n;i+) 从1n。但是1、2、3、4等不是5的倍数的数不可能含有5的因子呀,因此可将外循环修改为 for (i=5;i=n;i+=5) ,效率显然会提高些。毕竟外循环次数只有原来的五分之一。但将其再提交给 POJ 1401 “Factorial”,评测系统给出的结论仍然是:Time Limit Exceeded。 显然,要想不超时,可能的解决方法是将二重循环降成单重循环。如何做呢? (3)编程思路2。以求100!为例说明。设先将1100共100个数排成一行得到序列1。且设保存5的因子个数的变量cnt的初值为0。 序列1: 1 2 3 4 5 6 7 8 9 10 21 2

12、2 23 24 25 95 99 100 在序列1中,只有 5、10、15、99、100 共 100/5=20个数中至少含有一个5的因子。故cnt=cnt+n/5=0+20=20。 将序列1中的每个数除以5,只保留得到的整数,可排成序列2。(对应操作为n=n/5) 序列2: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 对应序列1的数为: 5 10 15 20 25 30 35 40 45 50 55 50 65 60 75 80 85 90 95 100 在序列2中,有20个数,只有20/5=4个数含有因子5,即原序列中有4个数(25,

13、50,75,100)至少含有两个因子5。 cnt=cnt+n/5=20+20/5=24。 再将序列2中的每个数除以5,只保留得到的整数,可排成序列3。(对应操作为n=n/5) 序列3 1 2 3 4 对应序列1的数为:25 50 75 100。 此时,序列3中不再有数能被5整除,即原序列中没有数含有3个5的因子。 cnt=cnt+n/5=24+4/5=24。 至此,求得100!末尾有24个0。 (4)源程序1-2。#include int main() int t,n,cnt; scanf(%d,&t); while(t-) scanf(%d,&n); cnt=0; while (n/5!=0

14、) cnt=cnt+n/5; n/=5; printf(%dn,cnt); return 0;提交给 POJ 1401 “Factorial” 时,评测系统给出的结论是:Accepted。 这个问题可以变形为较多的问题。例如,求n!能被7的最高多少次方整除?(由于7是一个质数,所以求得n!中含有因子7的个数就是问题的答案。);求n!能被9的最高多少次方整除?(由于9=3*3,因此不能直接求含有因子9的个数,先求出含有因子3的个数,再将得到的个数除以2取整就是问题答案。) POJ中问题2992 “Divisors”与例1的解决思路有关,但复杂得多。它求的是组合数c(n,k)的约数的个数,而组合数

15、c(n,k)=n!/(n-k)!*k!,因此问题会转化为求n!中各素因子的个数。为解决POJ 2992这个问题,我们通过例子的形式先逐步解决一些相关的简单问题。【例2】约数的个数。输入正整数n,求n的约数的个数。例如,输入24,24的约数有1、2、3、4、6、8、12、24共8个,因此输出8。(1)编程思路。最直接和简单的思路是用一个循环,将i从1sqrt(n)逐个试探,若n%i=0,则i是n的约数,n/i也是n的约数,约数个数增加2个。需要注意n是一个完全平方数的情况,此时约数个数只增加1。(2)源程序。#include int main() int n,cnt,i; while (scan

16、f(%d,&n) & n!=0) cnt=0; for (i=1; i*in; i+) if (n % i=0) cnt+=2; if (i*i=n) cnt+; printf(%dn,cnt); return 0;【例3】分解质因数。将一个正整数分解质因数。例如:输入90,输出 90=2*3*3*5。 (1)编程思路1。 对整数n进行分解质因数,应让变量i等于最小的质数2,然后按下述步骤完成: 1)如果i恰等于n,则说明分解质因数的过程已经结束,输出即可。 2)如果ni,但n能被i整除,则应输出i的值,并用n除以i的商,作为新的正整数n,转第1)步。 3)如果n不能被i整除,则用i+1作为新

17、的i值,转第1)步。 因此,程序主体是一个循环,在循环中根据n能否整除i,进行两种不同处理。 (2)源程序3-1及运行结果示例。#include int main() int n,i; while (scanf(%d,&n) & n!=0) printf(%d=,n); i=2; while(in) if(n%i=0) printf(%d * ,i); / i是n的因数,输出i n=n/i; / 对除以因数后的商再进行分解 else i+; / 找下一个因数 printf(%dn,n); return 0;运行源程序3-1,一个可能的运行示例如下:9090=2 * 3 * 3 * 512012

18、0=2 * 2 * 2 * 3 * 50从上面的运行示例可以看出,120分解质因数后,其因子2有3个,3有1个,5有1个。如果要求输出形式为: 120=23 * 31 * 51,怎么修改呢?(3)编程思路2。源程序3-1中,在循环处理时若i是当前n的因子,立即输出因子,由于相同因子可能有多个,因此在每个因子输出前需要用一个循环对含因子i的个数进行统计,统计完后再输出。并且为了方便后面使用,程序中将因子及其相应个数均用数组保存起来。(4)源程序3-2及运行示例。#include int main() int n,i,cnt,len; int p100,e100; while (scanf(%d,

19、&n) & n!=0) printf(%d=,n); len=0; for (i=2; i*i1; i+) if (n % i=0) / i是n的因子 cnt = 0; while(n % i=0) n /= i; cnt+; plen=i; / 保存因子i elen+=cnt; / 保存因子i的个数 if (n1) plen=n; elen+=1; for (i=0;i 2, there are no solutions with positive integral values for x, y and z. A proof of this theorem (called Fermats

20、last theorem) was found only recently by Andrew Wiles.Consider the following Diophantine equation:Diophantus is interested in the following question: for a given n, how many distinct solutions (i. e., solutions satisfying x y) does equation (1) have? For example, for n = 4, there are exactly three d

21、istinct solutions:Clearly, enumerating these solutions can become tedious for bigger values of n. Can you help Diophantus compute the number of distinct solutions for big values of n quickly?InputThe first line contains the number of scenarios. Each scenario consists of one line containing a single

22、number n (1 n 109).OutputThe output for every scenario begins with a line containing “Scenario #i:”, where i is the number of the scenario starting at 1. Next, print a single line with the number of distinct solutions of equation (1) for the given value of n. Terminate each scenario with a blank lin

23、e.Sample Input241260Sample OutputScenario #1:3Scenario #2:113(1)编程思路。这个问题是:已知n,求丢番图方程 1/n=1/x+1/y的整数解有多少组? 因为 1/n=1/x+1/y 所以 n=(x*y)/(x+y)(x+y)*n = x*y设x = n+a; y = n+b, 可得 n*n = a*b题目就转化成了求所有整数对(a,b),使得 a*b = n*n。即求n*n的约数个数,由于约数都是成对出现的,两数乘积为n*n。注意:n与n成对出现,而只计算了1次。因此,为避免重复,设n*n的约数个数为p,(p + 1)/2即为所求。

24、因此,本题的关键是要求出n*n的约数的个数。按照例2中的源程序采用的方法来解决这个问题不现实。因为:1)给定n的范围是1 n 109,n可能是一个很大的整数,n*n可能超出一个int型整数表数范围;2)即使采用64位整数避免了溢出的问题,但由于给定n可能很大,例2的源程序从i=2到i=sqrt(n)逐个试探,效率不高,会超时。因此,我们采用约数定理来求约数的个数。设 n 可以分解质因数:n=p1e1 p2e2 p3e3 pkak,由约数定义可知p1e1的约数有:p10, p11, p12.p1e1,共(e1+1)个;同理p2e2的约数有(e2+1)个.pkek的约数有(ek+1)个。故根据乘法

25、原理:n的约数的个数就是 (e1+1)(e2+1)(e3+1)(ek+1)。有了例3分解质因数的基础,在加上这个定理,就很容易求n*n的约数个数了。(2)源程序4-1。#include int main() int t,k,n,cnt,len,i,ans; int e101; scanf(%d,&t); for (k=1;k=t;k+) scanf(%d,&n); len=0; for (i=2; i*i1; i+) if (n % i=0) cnt = 0; while(n % i=0) n /= i; cnt+; elen+=cnt; if (n1) elen+=1; ans=1; for

26、 (i=0;ilen;i+) ans*=(2*ei+1); / ei保存的是n的因子i的个数,显然n*n得2倍 printf(Scenario #%d:n%dnn,k,(ans+1)/2); return 0;(3)换一种思路编写源程序。由于n可能很大,而将n分解质因数时,因子一定是一个质数,因此,我们可以先将sqrt(max_n)以内的质数先都求出来,这样试探因子时直接从2开始的质数一个一个找,会提高执行效率的。质数表的构造采用筛法来完成。直接给出源程序如下:#include #define maxn 34000 / 34000*34000=115600000010e9 int vismax

27、n;int primemaxn, prime_cnt;void get_prime() /筛法预处理出素数表 int i,j; for (i=0; imaxn;i+) visi = 1; vis0 = vis1 = 0; prime_cnt =0; for (i = 2; i maxn; i+) if (visi) primeprime_cnt+ = i; if(i*i = maxn) for (j = i * i; j maxn; j+=i) visj = 0; int main() int t,n,cnt,len,i,k,ans; int e101; get_prime(); scanf(%d,&t); for (k=1;k=t;k+) scanf(%d,&n); len=0; for (i=0; i1; i+) if (n % primei=0) cnt = 0; while(n % primei = 0) n /= primei; cnt+; elen+=cnt; if (n1) elen+=1; ans=1; for (i=0;ile

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1