题目

题意:输入一个n(0<=n<=10000),求 n! 的最低非零位的数字。如 5! = 120,得2。

分析:这种题好像以前见过好多次,(对,确实做过 = =,而且当年没做出来 = =!)。现在我是用记录每个质数有多少个来算的,把2跟5的去掉(2*5 = 10)。还要打表。n<=10000,872ms过的。

感觉应该有其他方法? 

其他解法补在下面。


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define bug(s) cout<<#s<<"="<<s

#define MAXN 10002
int p[MAXN];
int a[MAXN];
void prime()
{
    int n = MAXN;
    int idx = 0;
    memset(a, 0, sizeof(a));
    for(int i=2; i<=n; i++)
    {
        if(!a[i])
        {
            p[idx++] = i;
            for(int j=i*i; j<=n; j+=i)
                a[j] = 1;
        }
    }
}

int pn[MAXN];    //n!中相应质数的个数
int ans[MAXN];   // 打表
int main()
{
    int n;
    prime();
    ans[0] = 1;

    memset(pn, 0, sizeof(pn));
    int maxj = 0;
    for(int i=1; i<=10000; i++)
    {
        int x = i;
        for(int j=0; p[j]<=i; j++)      //每个质数
        {
            if(!p[j]) break;         //!!
            while(x%p[j] == 0) 
            {
                x/=p[j];
                pn[j]++;
                maxj = maxj>j? maxj: j;
            }
        }
        int cnt = pn[0]<pn[2]? pn[0]: pn[2];  //2 3 5 7...
        pn[0]-=cnt;
        pn[2]-=cnt;
        int ret = 1;
        for(int j=0; j<=maxj; j++)
        {
            for(int k=0; k<pn[j]; k++)  //次数
            {
                ret*=p[j];
                ret%=10;
            }
        }
        ans[i] = ret;
    }
    while(cin>>n)
    {
        printf("%5d -> %d\n", n, ans[n]);
    }
}


其他解法:

http://pageofcode.blogspot.com/2011/03/uva-568-just-facts.html(8ms......)

/* 568    C "Just the Facts" */

/* @BEGIN_OF_SOURCE_CODE */

#include <stdio.h>

#define FACT_UPTO 10001

int n, fact_lnzd[FACT_UPTO] ;

void precompute(void)
{
   int i, fact ;

   fact_lnzd[0] = fact_lnzd[1] = fact = 1 ;

   for (i=2; i<=FACT_UPTO; i++) {
      fact = fact * i ;
      while (fact%10==0)
         fact /= 10 ;
      fact = fact%100000 ;
      fact_lnzd[i] = fact%10 ;
   }
}

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

以及 http://blog.csdn.net/alfredtofu/article/details/6299296 提到的两个。

一、

//f(i)=f(i-1)*i%10,i%5=0;
//f(i)=mod(2,(n-1)%4+1))*f(n)%10,i%5!=0,n=i/5;
//mod(2,(n-1)%4+1))的取值范围是2,4,6,8
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <string>
using namespace std;
//#define TEST
long a[10001]={0, 1, 2, 6, 4, 2},b[5]={0, 2, 4, 8, 6};
int main() {
#ifdef TEST
	freopen("input.txt", "r", stdin);
#endif
	long m , n;
	for(long i = 6; i <= 10000; i++){
		m = i % 5;
		n = i / 5;
		if(m != 0) a[i] = a[i - 1] * i % 10;
		else a[i] = b[(n - 1) % 4 + 1] * a[n] % 10;
	}
	while(cin >> n) {
		printf("%5d -> %d/n", n, a[n]);
	}
	return 0;
}

二、

数论模板 = =!?

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <cstring>
using namespace std;
int lastdigit(char*buf)
{
   const int mod[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
   int len=strlen(buf),a[110],i,c,ret=1;
   if(len==1)
      return mod[buf[0]-'0'];
   for(i=0;i<len;i++)
      a[i]=buf[len-1-i]-'0';
   for(;len;len-=!a[len-1])
   {
      ret=ret*mod[a[1]%2*10+a[0]]%5;
      for(c=0,i=len-1;i>=0;i--)
         c=c*10+a[i],a[i]=c/5,c%=5;
   }
   return ret+ret%2*5;
}
int main() {
	char s[10];
	while(cin >> s) {
		printf("%5s -> %d/n", s, lastdigit(s));
	}
	return 0;
}