洛谷 P1134 阶乘问题

来源:洛谷 P1134 阶乘问题(来源的来源是USACO)

problem:

也许你早就知道阶乘的含义, N N N阶乘是由 1 1 1 N N N相乘而产生,如:

12 ! = 1 × 2 × 3 × 4 × 5 × 6 × 7 × 8 × 9 × 10 × 11 × 12 = 479 , 001 , 600 12!= 1 \times 2 \times 3 \times 4 \times 5 \times 6 \times 7 \times 8 \times 9 \times 10 \times 11 \times 12 = 479,001,600 12!=1×2×3×4×5×6×7×8×9×10×11×12=479,001,600

12 12 12的阶乘最右边的非零位为 6 6 6

写一个程序,计算 N ( 1 ≤ N ≤ 50 , 000 , 000 ) N(1 \le N \le 50,000,000) N(1N50,000,000)阶乘的最右边的非零位的值。

注意: 10 , 000 , 000 ! 10,000,000! 10,000,000! 2499999 2499999 2499999个零。

题解:(此处直接抄袭「luogu题解」及「luogu题解的题解」)
先不考虑n=1的情况。

  • N!的末尾只会是2,4,6,8(在此题中没有0).
  • [2,4,6,8]中任意一个数乘6,末尾仍是本身.
  • 末尾数字只受末尾数字影响(如果不是乘5的倍数),如 4 * 6得到的末尾数字与4 * 16的末尾数字一样.
  • 1*2*3*4*6*7*8*9的末尾是6,即答案只与「5的倍数」和「n%10后的数」有关。
  • 2*5=10,2*8=16,10和16乘以[2,4,6,8]都不会改变最后一位非零数,而因数5的个数不会多于因数2的个数,因此「每当要乘5时,转换成乘8」,结果不变,而乘8的结果是循环的。

综合以上,得出如下流程图:

n>0
n==0
ans=1,读入n
用n%10后的数更新ans
此时所有以1,2,3,4,6,7,8,9结尾的数相乘,末尾为6,不影响结果,可以删去
即此时保留的为1*5,2*5......n/5*5
替换为1*8,2*8,.....,n/5*8
将所有因数8共n/5个提出来,更新答案
n=n/5
ans为答案

至此,分析完成。
贴上题解答主karma的代码。

#include <cstdio>
using namespace std;
int n,ans=1;
int a[4]= {6,8,4,2};
int main() {
    scanf("%d",&n);
    while (n>0) {
        for (int i=1; i<=n%10;++i)//除了5之外,其他数字原样乘.
        //n%10 的原因:答案只受末尾数字影响 
            if (i!=5) ans=ans*i%10;//跳过乘5(此时可以放心%10) 
        n=n/5;//n/5即少乘了多少次5
        //即乘8的次数 
        ans=ans*a[n%4]%10;//四次一循环(此时可以放心%10) 
    }
    printf("%d",ans);
    return 0;
}

答主忘记特判n=1了,在此就不更改了。

2020.2.4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值