POJ 1150 The Last Non-zero Digit

Description

In this problem you will be given two decimal integer number N, M. You will have to find the last non-zero digit of the  NP M.This means no of permutations of N things taking M at a time.

Input

The input contains several lines of input. Each line of the input file contains two integers N (0 <= N<= 20000000), M (0 <= M <= N).

Output

For each line of the input you should output a single digit, which is the last non-zero digit of  NP M. For example, if  NP M is 720 then the last non-zero digit is 2. So in this case your output should be 2.

Sample Input

10 10
10 5
25 6

Sample Output

8
4
2


The first program

Consider the number N! factored into product of powers of prime numbers. It meansN!=2i * 3j * 5k * 7l * ... Note, that for eachN>1 the power i is greater than k. It means, that the last non-zero digit ofN! is the same as the last digit of N! / (2k * 5k). Therefore we can compute the result using the equation:

(N! / (2k * 5k)) mod 10 = ((N! / (2i * 5k)) mod 10 * 2i-k mod 10) mod 10

Number i can be obtained easily - we will divide eacha=1,2,...,N by 2 until the resulting number is not divisible by 2 and after each division we will add one to the variablei. Number k can be obtained in the same manner. Let f(i) denotes the number which we obtain by dividing i by the 2a * 5b where a and b are the highest numbers such that the i is divisible by this product. Number (N! / (2i * 5k)) mod 10 is equal to f(N!) mod 10 and can be computed as f(1) * f(2) * ... * f(N) mod 10. We will perform operation mod 10 after each multiplication in order to keep the resulting number as small as possible.

The advantege of this approach is that we do not need to implement arithmetics of large numbers. Some ideas used here are used in the second, more efficient program, as well.


The second program

The second program also computes the result as (2i-k mod 10 * f(N!) ) mod 10. Numbersi and k are computed much more efficiently. More precisely

i=N div 2 + (N div 2) div 2 + ((N div 2) div 2) div 2 + ...

(We get zero after finite number of divisions.) Numberk can be computed in the same way. After that we can compute i-k and we need to find 2i-k mod 10. Observe, that

21 mod 10 = 2, 22 mod 10 = 4, 23 mod 10 = 8, 24 mod 10 = 6, 25 mod 10 = 2, 26 mod 10 = 4, ...

i.e. the period is 4 and we need only to compute (i-k) mod 4 and then to find corresponding last digit. This observation can help us to simplify computation ofi and k - we do not need their exact values (that can be long) but we need only (i-k) mod 4.

We have shown how to compute 2i-k mod 10. Now let us considerf(N!) mod 10 = ((f(1) mod 10) * (f(2) mod 10) * ... * (f(N) mod 10)) mod 10. Note, thatf(i) mod 10 is always 1,3,7 or 9. If we knew, how many 3,7,9 are among (f(1) mod 10), (f(2) mod 10), ..., (f(N) mod 10), we could compute 3a mod 10, 7b mod 10, 9c mod 10 in the similar way as we did for 2i-k (last digits of powers of 3,7,9 are also periodical).


To compute the number of 3,7,9 among (f(1) mod 10), (f(2) mod 10), ..., (f(N) mod 10) is not so easy. We will divide numbers 1,2,...,N into groups so, that in each group are numbers with same quotient i/f(i) and we will compute number of 3,7,9 among (f(i) mod 10) for each such group separatelly (there areO(N2) such groups). First, let us consider a group in whichi/f(i)=1. This is the group of all numbers not divisible by 2 and 5. The number of 3,7,9 in this group is the same as number of 3,7,9 among 1 mod 10, 2 mod 10, ...,N mod 10. This number can be counted easily - it is N div 10 +a where a is 1 if the last digit of N is at least 3 (resp. at least 7 or at least 9). Now let us consider a group in whichi/f(i)=L (whereL=2a * 5b). We obtain this group by taking eachL-th number from the sequence 1,2,3,... and dividing it by L. It means that number of 3,7,9 for this group will be the same as the number of 3,7,9 among 1 mod 10, 2 mod 10, ..., (N divL) mod 10.


Now we know everything we needed for construction of a program. Since numbers in the input file are long, we need to implement arithmetics for long numbers. However, by careful implementation we can achieve that only division of a long number by small integer is necessary.


第一个程序不可取,当数据够大时,寻找i,k的时间太长

<span style="font-size:18px;">/** 
 * P(n,m)=n!/(n-m)!
 * 
 * 程序1:
 * 分析:
 *	 因为末尾的0都是由2(的倍数)*5(的倍数)产生的
 * 	把两者剔除即可,而2的倍数一般多于5的倍数,因此在计算结果时要将2^(i-k)乘进去
 * 	有以下公式:
 *    N!=2^i * 3^j * 5^k * 7^L * ...
 * 	  (N! / (2^k * 5^k)) mod 10 = ((N! / (2^i * 5^k)) mod 10 * 2^(i-k) mod 10) mod 10 
 * 	怎样得到i呢?
 * 	我们可以将每个a=1,2,3...N 除以2,直到不能除为止,每除一次变量i++
 * 	同理可得k
 * 
 * 	定义函数 simplify(n),它返回 (n/(2^a * 5^b)),也就是剔除 因子中2,5的倍数之后 所得的数
 * 	那么 (N! / (2^i * 5^k))mod 10=simplify(1)*simplify(2)*...*simplify(N) mod 10
 * 	(为了避免数字过大,因而每乘一次要 mod 10)
 * 
 * 算法:
 * 	1.接受输入,处理并获得 N M ,转换成 begin,end
 *  2.计算 i k,利用函数getTwo(N),getFive(N)
 *  3.计算(N! / (2^i * 5^k))mod 10, 利用函数simplify(N);
 *  4.得出最后结果,输出
 */
import java.util.Scanner;

public class POJ_1150_The_Last_Non_zero_Digit {

	private static int two = 0;
	private static int five = 0;

	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);

		while (input.hasNext()) {
			two=0;
			five=0;
			
			int begin = input.nextInt();
			int end = begin - input.nextInt() + 1;
			
			if(begin==end){ //P(n,1)的情况直接输出end
				System.out.println(end);
				continue;
			}
			
			int tempResult = 1;
			for (int i = end; i <= begin; i++) {
				tempResult = (tempResult * simplify(i)) % 10;
			}

			int result = (((int) Math.pow(2, two - five)) % 10 )* tempResult;
			System.out.println(result % 10);
			
		}
	}

	/**
	 * 返回除去所有2 5因子后的数 
	 */
	private static int simplify(int number) {
		// TODO Auto-generated method stub
		int powerTwo = getPower(number, 2);
		int powerFive = getPower(number, 5);

		two += powerTwo;
		five += powerFive;

		int div = ((int) Math.pow(2, powerTwo))
				* ((int) Math.pow(5, powerFive));

		return number / div;
	}

	/**
	 * 返回number的因子中whosePower的个数
	 * 
	 */
	private static int getPower(int number, int whosePower) {
		// TODO Auto-generated method stub
		int power = 0;
		int temp = number;

		while (true) {
			if (temp % whosePower == 0) {
				power++;
				temp = temp / whosePower;
			} else
				break;
		}
		return power;
	}
}</span>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值