题目
题意:输入一个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;
}