N!的从最末一个非0位开始自低位向高位数的第M位 soj 1115

                                     阶乘

N的阶乘定义为:N!=N×(N-1)×……×2×1

请编写一个程序,输出N的阶乘的十进制表示中从最末一个非0位开始自低位向高位数的第M位。

其中:0<=N<=10000,1<=K<=5

例如:N=5,M=2,结果是1(5!=120)  N=8,M=3,结果为0(8!=40320)

 

输入:

第一行一个整数M (1<=M<=100),代表测试数据的个数;

接下来M行,每行两个整数N,K

输出:

     输出M行,每行一个整数,即测试数据的结果。

 

样例:

输入:

2
5 2
8 3

输出:

1
0

题意:很明了,就是求n!十进制表示中的从最末一个非0位开始自低位向高位数的第M位。有种思路就是将n!求出来,直接计算。

这种方法耗时828ms,memory 692K。

#include<iostream>
#include
<string.h>
#include
<stdio.h>
#define MOD 10000
using namespace std;

int main(void)
{
int t;
scanf(
"%d",&t);
while(t--)
{
int i,j;
int n,k;
int digit,carry; //digit表示当前计算的值的位数,carry表示进位
int f[10000];
char s1[50000]={'\0'};
char s2[5];
long long temp;
f[
0]=1;
digit
=1;
scanf(
"%d%d",&n,&k);
for(i=2;i<=n;i++) //求n!
{
carry
=0;
for(j=0;j<digit;j++)
{
temp
=(long long)(f[j])*(long long)(i)+carry; //此处要用64位数据,防止数据溢出
f[j]
=temp%MOD;
carry
=temp/MOD;
}
while(carry)
{
f[digit
++]=carry%MOD;
carry
=carry/MOD;
}
}
i
=digit-1;
while(f[i]==0)
{
i
--;
}
sprintf(s2,
"%d",f[i]);
strcat(s1,s2);
i
--;
for(;i>=0;i--) //将结果存进字符数组中以便于处理
{
sprintf(s2,
"%04d",f[i]); //不足4位前面补0
strcat(s1,s2);
}
for(i=strlen(s1)-1;i>=0;i--)
{
if(s1[i]!='0')
break;
}
printf(
"%d\n",s1[i-k+1]-48);
}
return 0;
}

下面是另外一种思路

由于是求最末一个非0位开始自低位向高位数的第M位,那么末尾的0则可以忽略掉,并且最多只需保存5位结果即可(M<=5)。

如:n!=A1A2A3..........Ai000000000 Ai!=0

则只需取A(i+4)A(i+3)A(i+2)A(i+1)Ai这5位即可.

耗时0ms,memory 580K,明显效率高很多。

#include<iostream>
#define MOD 100000
using namespace std;

int main(void)
{
int t;
scanf(
"%d",&t);
while(t--)
{
int n,k;
int i,ans;
ans
=1;
scanf(
"%d %d",&n,&k);
for(i=n;i>=2;i--)
{
ans
*=i;
while(ans%10==0) //消除末尾的0
{
ans
/=10;
}
if(ans>=MOD) //只需保存末尾5位数字即可
ans%=MOD;
}
for(i=1;i<k;i++)
{
ans
=ans/10;
}
ans
=ans%10;
printf(
"%d\n",ans);
}
return 0;
}
原文地址:https://www.cnblogs.com/dolphin0520/p/2014460.html