题目大意:给出n,m,求P(n,m)最后一位末尾非0数字



解题思路:已知P(n,m)=n!/(n-m)! 由于n,m<=200000000


这里利用到数论中求n!最尾非零数的非零数字的方法(下列数字2,5,1,3,7,9均表示数的个位):


1)因为2,5组成10,故可以删去能配对的2,5,记录下剩余2的个数;(2显然多于5)


2)每一个数,在mod2,5之后只有1,3,7,9四种结果,1可以忽略不计,故我们只需要统计3,7,9的个数

统计方法如下:f(n,x)和g(n,x)中的n代表n!中的n,x取3,7,9中的一个

有:f(n,x)=f(n/2,x)+g(n,x)

g(n,x)=n/10+g(n/5,x)+k

if (n>=x) k=1; else k=0;

这里面是将阶层中的项分为奇数项和偶数项,其中先对奇数项求3,7或9的个数。这里面,很容易知道,每10个数里面一定有一个以3,7或者9结尾的数,而且当n>=3,7或9时,必存在一个3,7,9(当n=16时,前10个数有一个以3结尾,而13也是以上结尾,所以此处有两个3,不是n/10);另外由于要约去成对的2和5那么无可避免的会出现其他的数字(2,3,7,9,1,其中2另外考虑),所以此处要加上g(n/5,x)。对于偶数项,不难发现当偶数项除以2(这里的2由于有另外统计,所以除后对结果没有影响)后就变成了n!的前一半(如10!有1,2,3,4,5,6,7,8,9,10,偶数项除以而后可以转化为1,2,3,4,5。)。

3)最后,找规律,如出现几个2的乘积末尾是多少~~

代码:

 

 1 #include  < cstdio >
 2 #include  < string >
 3 #include  < iostream >
 4 using   namespace  std;
 5
 6 int  n,m,a,b,c,temp,temp1,d;
 7 int  p( int  n, int  x)
 8 {
 9    if(n<x) return 0;
10    return n/x+p(n/x);
11}

12 int  g( int  n, int  x)
13 {  if (n<1return 0;
14   else
15     if (n%10>=x) return n/10+1+g(n/5,x);
16     return n/10+g(n/5,x);
17}

18 int  f( int  n, int  x)
19 {  if (n<1return 0;
20   else return f(n/2,x)+g(n,x);
21}

22 void  working()
23 int k;
24  a=f(n,3)-f(n-m,3);
25  b=f(n,7)-f(n-m,7);
26  c=f(n,9)-f(n-m,9);
27  temp=p(n,5)-p(n-m,5);
28  temp1=p(n,2)-p(n-m,2);
29  d=temp1-temp;
30  if (a%4==0) a=1else
31  if (a%4==1) a=3else
32  if (a%4==2) a=9else
33  if (a%4==3) a=7;
34
35  if (b%4==0) b=1else
36  if (b%4==1) b=7else
37  if (b%4==2) b=9else
38  if (b%4==3) b=3;
39
40  if (c%4==0) c=1else
41  if (c%4==1) c=9else
42  if (c%4==2) c=1else
43  if (c%4==3) c=9;
44
45  if (d%4==0) d=6else
46  if (d%4==1) d=2else
47  if (d%4==2) d=4else
48  if (d%4==3) d=8
49
50  printf("%d\n",a*b*c*d%10);
51
52}

53 int  main()
54 {  while (scanf("%d%d",&n,&m)!=EOF)
55   { working();
56   }

57
58}

59