码迷,mamicode.com
首页 > 其他好文 > 详细

【hoj】1013just the facts

时间:2014-07-01 15:00:55      阅读:269      评论:0      收藏:0      [点我收藏+]

标签:hoj   java解决   阶乘   高精度   

首先,这个题是要求出给定数字的阶乘结果的倒数第一个不为0 的尾数,这需要我们通过阶乘的性质归纳总结出一定的规律,其次,由于题目要求的数字较大,对于高精度的数据可以适当采用java来求解

原文链接http://blog.csdn.net/rappy/article/details/1903360

首先对数列 d [10] = {1, 1, 2, 3, 4, 1, 6, 7, 8, 9} 和
ff [10] = {1, 1, 2, 6, 4, 4, 4, 8, 4, 6}
有 d [0] * ... * d [i] % 10 = ff [i],0 <= i < 10。

对于 n < 5 直接输出 ff [n] 即可。
对于 n >= 5,例如 n = 26,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
的乘积等于
1 2 3 4 1 6 7 8 9  1 11 12 13 14  1 16 17 18 19  1 21 22 23 24  1 26
的乘积再乘上 5 10 15 20 25 的乘积,而5 10 15 20 25 的乘积等于
1~26/5 的乘积再乘上 526/5

先考虑
1 2 3 4 1 6 7 8 9  1 11 12 13 14  1 16 17 18 19  1 21 22 23 24  1 26,
可以 10 个 10 个地分成几组。
其中 1 2 3 4 1 6 7 8 9 1,11 12 13 14  1 16 17 18 19  1 这两组数的乘积
都为 10*q + 6 的形式,两个乘积乘起来还是 10*q + 6 的形式。
而 21 22 23 24  1 26 这组数的乘积则是 10*q + ff [26%10] = 10*q + 4的形式,
因此 3 组数的乘积是 10*q + 4 的形式,这个 4 由 ff [26%10] * 6 % 10 所得。

因此 26! = (26/5)! * 526/5 * (10*q+4) = (26/5)! * 1026/5 * [(10*q+4) / 226/5],
则 26! 的最后一个非零数字为 (26/5)! * [(10*q+4) / 226/5]
注意到除了0! 和 1!,阶乘的最后一个非零数字必为偶数,所以有一个规律:
(10*q + 2) / 2 = 10*q‘ + 6
(10*q + 6) / 2 = 10*q‘ + 8
(10*q + 8) / 2 = 10*q‘ + 4
(10*q + 4) / 2 = 10*q‘ + 2
每除以 2 四次,尾数就循环一次。因此
(10*q+4) / 226/5 的尾数即 (10*q+4) / 226/5%4,这个可以用以下代码计算:
t = ff [n % 10] * 6 % 10;
for (int i = 1; i <= n / 5 % 4; i ++)
    {
    if (t == 2 || t == 6) t += 10;
    t /= 2;
    }

计算出来的 t 即为 (10*q+4) / 2^(26/5) 的尾数,然后用 t 乘以 (26 / 5)! 的最后
一个非零数字再对 10 取模即得到 26! 的最后一个非零数字而计算 (26 / 5)! 的最后
一个非零数字可以使用递归处理。

综上,设 F(N) 为 N! 最后一个非零数字,则有以下递归式:
F(N) = ff [N]   (N < 5)

             F([N/5]) * ff [N的尾数] * 6
F(N) = ----------------------------------- (N >= 5)

                 2[N/5] % 4

因此算法的时间复杂度是 O(log5N) 的。
即使 N 达到 10100,也可以很快计算出来,不过需要使用高精度整数,整除 5 也即
乘以 2 再整除 10,而乘以 2 也即自加,整除 10 也即截掉最后一位数字。
而对 4 取模只要取最后两位数字对 4 取模即可,例如 1234 % 4 = 34 % 4 = 2。
因此实现起来相当方便。

#include <cstdio>
using namespace std;

const int ff [10= {1126444846};

int f (int n)
    {
    
if (n < 5return ff [n];
    
int t = ff [n % 10* 6 % 10;
    
for (int i = 1, r = n / 5 % 4; i <= r; i ++)
        {
        
if (t == 2 || t == 6) t += 10;
        t 
/= 2;
        }
    
return f (n / 5* t % 10;
    }

int main ()
{
    
int n;
    
while (scanf ("%d"&n) != EOF)
        {
        printf (
"%5d -> %d ", n, f (n));
        }
    
return 0;
}

java解决:

 

import java.util.*;
import java.math.*;
public class Main
{
    static int [] hash = {6, 6, 2, 6, 4, 4, 4, 8, 4, 6};
    static int [] one_digit_hash = {1, 1, 2, 6, 4, 2, 2, 4, 2, 8};
    static BigInteger five = BigInteger.valueOf(5),four=BigInteger.valueOf(4),ten=BigInteger.valueOf(10);
    public static int calc(BigInteger num)
    {
        if(num.compareTo(ten)==-1)
            return one_digit_hash[(int)num.longValue()];
        else
        {
            int mod = (int)num.divide(five).mod(four).longValue();
            String str = num.toString();
            int ret = hash[str.charAt(str.length()-1)-'0'];
            ret=ret*calc(num.divide(five)) % 10;
            while(mod-- >0)
                ret=ret*8%10;
            return ret;
        }
    }
    public static void main(String[] args)
    {
        Scanner cin =new Scanner (System.in);
        BigInteger num;
        while(cin.hasNextBigInteger())
        {
            num=cin.nextBigInteger();
            System.out.println(calc(num));
        }
    }
}

【hoj】1013just the facts,布布扣,bubuko.com

【hoj】1013just the facts

标签:hoj   java解决   阶乘   高精度   

原文地址:http://blog.csdn.net/ymzmdx/article/details/36175069

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!