poj 1150 The Last Non-zero Digit

The Last Non-zero Digit
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 5363   Accepted: 1642

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 Output8

4
2

题意:求A(n,m)的最后一个非零末尾,A(n,m)即n!/(n-m)!
思路:先把A(n,m)中的所有2和5因子提取出来,考虑剩余部分的积的末尾,这可以表示为A(n,m)/(2^a*5^b)
,其中a,b为2,5的因子个数,那么剩余部分的因子结尾一定为3,7,9,可以先把这部分的乘积的末尾求出来(3,7,9的n次方的末尾数都是4个1循环,方便求得),之后再结合因子2和5,若5的个数多于2,最终结尾一定为5,若2的个数多于5,多出来的2^(a-b)
末尾也是4个数一循环,可以方便求出来。

那么现在的关键是如何求得因子结尾是3,7,9的那些数的个数,我么可以将n!分成两个数列,奇数列和偶数列,先看奇数列,奇数列中每间隔10都会出现一个3,7,9的数,最后间隔小于10的部分则考虑剩余部分间隔是否大于x(3,7,9),若x大于间隔,则存在一个以x结尾的因子.考虑到数列中有5的倍数,n/5递归数列继续以上的操作。
偶数列不断递归除以2也能得到奇数列。
AC代码:


#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<string>
#include<queue>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f
const int N_MAX = 20000000+4;
int n,m;
//计算n!中x的因子个数
int prime_num(int n, int x) {
    int num = 0;
    while(n) {
        num += n / x;
        n /= x;
    }
    return num;
}
//计算n!以3,7,9结尾的因子的个数
int odd_end_with(int n,int x) {
    if (n == 0)return 0;
    return n / 10 +((n%10)>=x)+odd_end_with(n / 5, x) ;
}
int end_with(int n,int x) {
    if (n == 0)return 0;
    return odd_end_with(n,x) + end_with(n/2,x);
}
int table[4][4] = {
  6, 2, 4, 8,//2
  1, 3, 9, 7,//3
  1, 7, 9, 3,//7
  1, 9, 1, 9//9
};


int main() {
    while (scanf("%d%d",&n,&m)!=EOF) {
        int two = prime_num(n, 2) - prime_num(n - m, 2);
        int five = prime_num(n, 5) - prime_num(n - m, 5);
        if (five > two) { printf("5
"); continue; }

        int three = end_with(n, 3) - end_with(n - m, 3);
        int seven = end_with(n, 7) - end_with(n - m, 7);
        int nine = end_with(n, 9) - end_with(n - m, 9);
        int res = 1;
        if(two>five)res *= table[0][(two - five) % 4];
        res *= table[1][three % 4];
        res *= table[2][seven % 4];
        res *= table[3][nine % 4];
        res %= 10;
        printf("%d
",res);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ZefengYao/p/7783302.html