阶乘问题 【数论】

题目来源  

  洛谷1134    https://www.luogu.org/problemnew/show/P1134

题目简述

   求 N!中最右侧第一个非零项    (命名为有效位)

输入输出格式

  输入格式:

  仅一行包含一个正整数 NN 。

  输出格式:

  一个整数,表示最右边的非零位的值。  

分析

  对于任意 N>1  

  有效位只能为 2,4,6,8     

  观察这几个数之间的连系(我的着手点为2进制)

    2=2

    4=2x2

    8=2x2x2

    6=2x2x2x2 (有效位)

    2=2x2x2x2x2

    4=2x2x2x2x2x2

    ......

  那么可以得到 

    在这四个数中,

      任意数 x6 得到其本身 

      任意数 x8 等价于减少一个 x2   (2=2x2x2x2x2)  

  接着,对于所有存在的个位数字    (因为需要排除个位为零导致十位数字参与运算的干扰,排除数字5,0)

      1x2x3x4x6x7x8x9=6 (72576有效位为6)

      而根据前文分析 ,x6是只会无意义的

    所以对于 10*(k+1)>N>10*k 时 (1~10*k) 的相乘是无意义的

      即我们只需要计算 N的个位相乘

   最后再看我们先前忽略的干扰数字:

      0     无法带来任何改变 ,忽略

        对于 2x2x2x..x2  的一个数来说   x5 等价于减少一个 x2  ,也就是说 x5 等价于 x8  (我们这么做的目的是为了排除x5所导致对十位数字的计算)。而因为1~N中因数5的系数是连续的(例如N=32  具有1x5,2x5,3x5,4x5,5x5,6x5 共6(32/5)个5需要特殊处理,且其中系数1,2,3,4,5,6是连续且需要计算的,运算过程直接当成 N=6算即可)

 

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 int N;
 8 void Read(int &x){
 9     x=0;
10     char c=getchar();
11     while(!isdigit(c)) c=getchar();
12     while(isdigit(c)) x=x*10-'0'+c,c=getchar();
13     return ;
14 }
15 void Write(int x){
16     int np=0;
17     int s[505];
18     while(x) s[++np]=x%10,x/=10;
19     while(np) putchar(s[np--]+'0');
20     putchar('\n');
21     return ;
22 }
23 int E[4]={6,8,4,2};     //乘8的有效位(以4为周期的数列) 
24 int main(){
25     Read(N);
26     int ans=1;
27     while(N){
28         for(int i=1;i<=(N%10);i++)
29         if(i!=5) ans=(ans*i)%10;
30         N/=5;    //计算特殊处理的5  和  这些5的系数 
31         ans=(ans*E[N%4])%10;
32     }
33     Write(ans);
34     return 0;
35 }
CODE

 

      

    

  

posted @ 2018-07-12 14:06  Wannabtl  阅读(493)  评论(0编辑  收藏  举报