阶乘数最右边一个非零数字:通用解法

来源:互联网 发布:激光雕刻切割机软件 编辑:程序博客网 时间:2024/06/06 07:44
  做题时发现了一个奇怪的问题:给出正整数n(可能有前导0),请求出n!最右非零的数位的值。那么这道题肿么做呢???
  USACO中有一道类似的题目,不过数据范围要小很多。。。n只有106,直接一个爆搞取模 1000000 即可但是这道题中数据范围有10100,暴力的话。。。估计没有那么几个世纪是运行不出来的。。。考试的时候也没有想出什么好的方法,就暴力(暴力大法好)搞了10分。。
  然后考试后,根据lyc大爷的博客 http://luoyuchu.logdown.com/posts/257468-oi-seeking-n-the-right-of-non-zero-numbers 写出了一份代码,但是又发现owaski大爷有一种更好的算法,于是继续学习
  PS:其实这种算法应该说是一种数学做法,是别人从数竞书上看到的。。。
  首先我们知道一点,因为1n2的因子一定比5的因子多,所以求 n! 的末尾0的个数的做法就是找1n中有多少个5的因子,也就是说

Tn=[n5]+[n25]+[n125]+[n625]+[n3125]+[n15625]+

  有一些奇怪的方法得知,这个最右非零的数位上的数一定是一个偶数,也就是2,4,6,8中的一个。
  设n=5k+tn!最右非零的数位的值为f(n),因为有以下式子:

(5k)!
=(1234)(6789)...[(5k4)(5k3)(5k2)(5k1)](5101520...5k)
=(1234)(6789)...[(5k4)(5k3)(5k2)(5k1)]5kk!
=12k(1234)(6789)...[(5k4)(5k3)(5k2)(5k1)]10kk!

  也就是说,f(n)12k(1234)(6789)...[(5k4)(5k3)(5k2)(5k1)]k!t!
  我们忽略k!t!继续化简,可以得到:

12k(1234)(6789)...[(5k4)(5k3)(5k2)(5k1)]
12k6k(1234)(6789)...[(5k4)(5k3)(5k2)(5k1)](mod 5)
=3k(1234)(6789)...[(5k4)(5k3)(5k2)(5k1)]
3k(1234)k(mod 5)
=72k
2k(mod 5)

  很明显答案一定是偶数,所以如果f(n)mod5为奇数的话f(n)mod10=f(n)mod5+5,而f(n)mod5为偶数的话f(n)mod10=f(n)mod5,对于k!我们可以进行同样的操作,直到此数小于5为止。
  下面进行一个模拟操作,我们拿104做例子

bu yao wen wo wei shen me shi 104
zhe zhi shi yi ge sui ji shu er yi...
104!
22020!4!(mod 5)
220244!4!(mod 5)
6644(mod 5)
6(mod 10)

  经过暴力程序的验证,这个答案是正确的,在经过各种对拍,可以确定这就是正解!!!
  下面不附上代码。。。因为长得丑。。。233
0 0
原创粉丝点击