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

[复制链接]
607|8
 楼主| functions 发表于 2019-9-14 18:09 | 显示全部楼层 |阅读模式
                                     阶乘
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)

 楼主| functions 发表于 2019-9-14 18:09 | 显示全部楼层
输入:

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

接下来M行,每行两个整数N,K
 楼主| functions 发表于 2019-9-14 18:09 | 显示全部楼层
输出:

     输出M行,每行一个整数,即测试数据的结果。
 楼主| functions 发表于 2019-9-14 18:10 | 显示全部楼层
样例:

输入:

2
5 2
8 3

输出:

1
0
 楼主| functions 发表于 2019-9-14 18:10 | 显示全部楼层
题意:很明了,就是求n!十进制表示中的从最末一个非0位开始自低位向高位数的第M位。有种思路就是将n!求出来,直接计算。

这种方法耗时828ms,memory 692K。
 楼主| functions 发表于 2019-9-14 18:10 | 显示全部楼层
  1. #include<iostream>
  2. #include<string.h>
  3. #include<stdio.h>
  4. #define MOD 10000
  5. using namespace std;

  6. int main(void)
  7. {
  8.     int t;
  9.     scanf("%d",&t);
  10.     while(t--)
  11.     {
  12.         int i,j;
  13.         int n,k;
  14.         int digit,carry;       //digit表示当前计算的值的位数,carry表示进位
  15.          int f[10000];
  16.         char s1[50000]={'\0'};
  17.         char s2[5];
  18.         long long temp;
  19.         f[0]=1;
  20.         digit=1;
  21.         scanf("%d%d",&n,&k);
  22.         for(i=2;i<=n;i++)      //求n!
  23.         {
  24.             carry=0;
  25.             for(j=0;j<digit;j++)
  26.             {
  27.                 temp=(long long)(f[j])*(long long)(i)+carry; //此处要用64位数据,防止数据溢出
  28.                   f[j]=temp%MOD;
  29.                 carry=temp/MOD;
  30.             }
  31.             while(carry)
  32.             {
  33.                 f[digit++]=carry%MOD;
  34.                 carry=carry/MOD;
  35.             }
  36.         }
  37.         i=digit-1;
  38.         while(f[i]==0)
  39.         {
  40.             i--;
  41.         }
  42.         sprintf(s2,"%d",f[i]);
  43.         strcat(s1,s2);
  44.         i--;
  45.         for(;i>=0;i--)            //将结果存进字符数组中以便于处理
  46.          {
  47.             sprintf(s2,"%04d",f[i]);   //不足4位前面补0
  48.             strcat(s1,s2);
  49.         }
  50.         for(i=strlen(s1)-1;i>=0;i--)
  51.         {
  52.             if(s1[i]!='0')
  53.                 break;
  54.         }
  55.         printf("%d\n",s1[i-k+1]-48);
  56.     }
  57.     return 0;
  58. }
 楼主| functions 发表于 2019-9-14 18:11 | 显示全部楼层
下面是另外一种思路

由于是求最末一个非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,明显效率高很多。
 楼主| functions 发表于 2019-9-14 18:11 | 显示全部楼层
  1. #include<iostream>
  2. #define MOD 100000
  3. using namespace std;

  4. int main(void)
  5. {
  6.     int t;
  7.     scanf("%d",&t);
  8.     while(t--)
  9.     {
  10.         int n,k;
  11.         int i,ans;
  12.         ans=1;
  13.         scanf("%d %d",&n,&k);
  14.         for(i=n;i>=2;i--)
  15.         {
  16.             ans*=i;
  17.             while(ans%10==0)        //消除末尾的0
  18.             {
  19.                 ans/=10;
  20.             }
  21.             if(ans>=MOD)           //只需保存末尾5位数字即可
  22.                 ans%=MOD;
  23.         }
  24.         for(i=1;i<k;i++)
  25.         {
  26.             ans=ans/10;
  27.         }
  28.         ans=ans%10;
  29.         printf("%d\n",ans);
  30.     }
  31.     return 0;
  32. }
 楼主| functions 发表于 2019-9-14 18:11 | 显示全部楼层
作者:Matrix海子
    
出处:http://www.cnblogs.com/dolphin0520/
    
本博客中未标明转载的**归作者Matrix海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在**页面明显位置给出原文连接,否则保留追究法律责任的权利。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

39

主题

446

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部