您的位置:首页 > 其它

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

2011-04-13 10:22 260 查看
阶乘

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐