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 NPM.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 NPM. For example, if NPM 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>


發佈了14 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章