UVa568:Just the Facts

UVa568:Just the Facts


题目大意


给定一个数字n,求n!的最后一位非零数字。

例:当n为5的时候,n!为120,所以答案是2;
当n为7的时候,n!为5040,所以答案为4。

Solution


因为阶乘可能会非常大并且最后一位非零数字和前面的数字无关,所以很直观的想法是只保留非零的、最后的若干位数字。

所以关键就是要保留多少位的问题,最开始我只保留了一位,但很快就出现问题了。比如说保留的数字是2,下一个需要乘起来的数字是15,这样就会得到30,除去末尾的0就得到了3,而显然,这里的答案是有问题的,正确答案应该和更高位的数字有关,而这个数字被我们舍弃了。

经过我的几番尝试,发现保留5位数字可以得到正确的答案。逆推了一下原因,因为本题中最大的n是10000,所以与一位数字相乘能得到的最大数字是90000,保留五位数字就可以保证所有关键信息不被舍弃。

而理论上应该是保留位数越多越好,因此如果保留6位或者更多位数的话应该依然会得到正确结果,但我试了一下,发现错了。原因是,我采用int存储数据,如果保留的数字超过5位,在进行乘法的时候就有可能会造成溢出,所以5位数字就成了一个本题中的magic number(当然,如果采用long long存储数据也可以规避上述溢出问题)。

AC-Code(C++)


Time:0ms

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <climits>
#include <ctime>

using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 10000 + 10;

int dp[maxn];

int fact(int x){
    if(dp[x] != -1)
        return dp[x];
    dp[x] = x * fact(x-1);
    while(dp[x] % 10 == 0)
        dp[x] /= 10;
    dp[x] %= 100000;// a magic number....
    // 10 100 1000 10000 are not big enough, since the bigest n can be 10000
    // 1000000 is too large can result in overflow
    return dp[x];
}

int main(int argc, const char * argv[]) {
    
//    freopen("input.txt", "r", stdin);
    
    int n;
    memset(dp, -1, sizeof(dp));
    dp[0] = 1;
    while(scanf("%d",&n)==1){
        printf("%5d -> %d\n",n,fact(n)%10);
    }

    return 0;
}

posted @ 2018-02-02 00:52  Irran  阅读(274)  评论(0编辑  收藏  举报