题意:

要求你求出n!(n−m)!)\frac{n!}{(n-m)!)}(n−m)!)n!​中最后一个非0的数字.

题目:

In this problem you will be given two decimal integer numberN,M. You will have to find the last non-zero digit of the NPM^{N}P_{M}NPM​.This means no of permutations of N things taking M at a time.

Input

The input contains several lines of input. Each line of the input file contains two integers N (0 <= N<= 20000000), M (0 <= M <= N).

Output

For each line of the input you should output a single digit, which is the last non-zero digit of NPM. For example, if NPM^{N}P_{M}NPM​ is 720 then the last non-zero digit is 2. So in this case your output should be 2.

Sample Input

10 10
10 5
25 6

Sample Output

8
4
2

分析:

说实话这道题上来我就没看懂题意,这怎么就NPM^{N}P_{M}NPM​==n!(n−m)!)\frac{n!}{(n-m)!)}(n−m)!)n!​了?In a word ,我感觉到了不友好。
然后我就开始了啃书环节,具体在《挑战程序设计》P293,之后恶意铺面而来,花费我一晚上,终于摸透了这个题,必须滴好好说道说道。
(1)首先是若求n!的最后一位,我们可以将所有的因数10去掉,问题就转换为了求这个数的最后一位。根据以往的做题经验,这时候只要找到所有的因子2和5,放着对最后特判对于最后一位的影响就好了,所以正常while循环暴力找因子数,然后超时了,代码如下:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;const int N=2e7+10;
int a[5][N];
int b[5][4]={{6,2,4,8},{5,5,5,5},{1,3,9,7},{1,7,9,3},{1,9,1,9}};
int get(int x){if(x==2) return 0;if(x==5) return 1;if(x==3) return 2;if(x==7) return 3;if(x==9) return 4;
}
void init(){for(int i=2; i<N; ++i){int t=i;int su=0,sm=0;while(t%2==0) t/=2,++su;while(t%5==0) t/=5,++sm;a[get(2)][i]=a[get(2)][i-1]+su;a[get(5)][i]=a[get(5)][i-1]+sm;a[get(3)][i]=a[get(3)][i-1];a[get(7)][i]=a[get(7)][i-1];a[get(9)][i]=a[get(9)][i-1];if(t%10 && t%10!=1) ++a[get(t%10)][i];}
}int main()
{init();int n,m;while(~scanf("%d%d",&n,&m)){int su=a[get(2)][n]-a[get(2)][n-m];int sm=a[get(5)][n]-a[get(5)][n-m];if(su<sm) printf("5\n");else {//printf("+++++++ %d %d\n",su,sm);su-=sm;int d3=a[get(3)][n]-a[get(3)][n-m];int d7=a[get(7)][n]-a[get(7)][n-m];int d9=a[get(9)][n]-a[get(9)][n-m];int tmp=b[get(3)][d3%4]*b[get(7)][d7%4]*b[get(9)][d9%4];//printf("+++++++++ %d %d\n",su,tmp);tmp*=su?b[get(2)][su%4]:1;int ans=tmp%10;printf("%d\n",ans);}}return 0;
}

这并不冤枉,其实开数组2e7就该知道有问题,试了编译器,可以运行,就硬着头皮写下来了,不出意料,果真超时了。那这里就用到了“白书”的定理,我懒得敲了。

具体代码如下:

int sum(int n,int p){//计算n!中质因子m的出现次数return n==0?0:n/p+sum(n/p,p);
}

(2)当我们对(1~n)去除因子2,5后发现最后一位的值,只可能是 1,3, 7,9这四个数,因为最后一位若为1,n!相乘对最后一位值的变化没有影响,所以可以不用考虑,只考虑 3,7 ,9,即可。这时发现了规律,例如,即当存在多个3时,只考虑个位值,出现了循环节{1,3,9,7},注意第一位为整除时,所以为值为1。你以为到这就算完了,还不够!

(3)如上超时代码,不能打表开数组存,所以每次输入就直接调用函数,直接对n!进行讨论,将其分为奇偶两个部分:
【1】对于偶数序列,我们只需将它除 2 即可递归转化为奇数序列(其实就是消去因子2)。
【2】对于奇数序列,我们可以发现,每 10个数字中就有 3 , 7 , 9 各一个,但又因为(1~n)中有 5的倍数,所以继续除 5,递归消去因子。
(4)这里就差不多了,但还是要注意:
一,当因子2的个数小于5的个数时,由于此时末尾必为奇数(1,3,7,9中一个),所以相乘最后一位必为5,直接输出。
二,当因子2的个数大于5的个数时,需要考虑因子2对结果的一个影响,这时也有与前面一样的规律{6,2,4,8},理解了之后让我们欢乐敲代码吧;

AC模板:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m;
int e[4][4]={{6,2,4,8},{1,3,9,7},{1,7,9,3},{1,9,1,9}};
int sum(int n,int p){//计算n!中质因子m的出现次数,用到“挑战程序设计”P293推论return n==0?0:n/p+sum(n/p,p);
}
int odd(int n,int p){//奇数数列中末尾为x的数出现的次数,消去1~n数中存在的因子5return n==0?0:n/10+(n%10>=p)+odd(n/5,p);
}
int even(int n,int p){//末尾为x的数的出现次数,消去1~n数中存在的因子2;return n==0?0:even(n/2,p)+odd(n,p);
}
int main()
{while(~scanf("%d%d",&n,&m)){int su=sum(n,2)-sum(n-m,2);int sm=sum(n,5)-sum(n-m,5);int a=even(n,3)-even(n-m,3);int b=even(n,7)-even(n-m,7);int c=even(n,9)-even(n-m,9);if(su<sm){printf("5\n");continue;}int ans=e[1][a%4]*e[2][b%4]*e[3][c%4]%10;if(su!=sm)ans*=e[0][(su-sm)%4];printf("%d\n",ans%10);}return 0;
}

备战ccpc分站赛ing ,题目分析简略,见谅,转载请注明出处。。。。。

The Last Non-zero Digit POJ - 1150(n!mod p)相关推荐

  1. H - Fibonacci POJ - 3070 (矩阵快速幂)

    H - Fibonacci POJ - 3070 (矩阵快速幂) Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and ...

  2. POJ - 2386 (dfs简单应用)

    POJ - 2386 (dfs深度优先搜索) 题目正文: Due to recent rains, water has pooled in various places in Farmer John' ...

  3. poj 1061 (扩展欧几里德算法)

    首先先抛出一个例题:            青蛙的约会 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 89761   Acc ...

  4. The Water Bowls POJ - 3185(开关问题+暴力)

    题意: 给20个水碗.朝上为'0'或朝下为'1',每次操作使三个碗翻转,问使所有20个水碗都朝上,至少翻多少次? 题目: The cows have a line of 20 water bowls ...

  5. POJ 1723(中位数+连续排列)

    题目大意:有N个士兵,每个士兵开始站的坐标是(x,y),现在使得将N个士兵站在同一个水平线(即所有士兵的y坐标相同)并且x坐标相邻,每个士兵每次可以移动一个位置(分别在x和y方向移动).求出最少的移动 ...

  6. 关于digit统计算法(C语言实现)

    在练习题目的时候,遇到了这个问题:对输入的整数进行digit的处理.具体处理如:统计完全平方数且有至少两个字位相同. 最初的想法是需要一个数组进行存储计算出来的数位,再遍历判断是否有两个相同的数位. ...

  7. poj 3348(求凸包面积)

    题意:一片草地上有n课树,现在你想用绳子圈出一个尽可能大的面积出来养牛.已知每只牛需要50单位的面积,问最多能养几只牛. 解题思路:凸包的面积.这里一般的思路就是先求出凸包,再以最低点为顶点分割n-2 ...

  8. poj 1324(BFS+状态压缩)

    解题思路:这道题一开始的想法就是状态压缩,即考虑如何判重,由于蛇并非是直线的,所以想到了以每一个点的上下左右共四个 值来表示相对位置.最开始想如何用四进制来表示它,无语.....还是题目做少了,直接用 ...

  9. Cow Contest POJ - 3660(floyed求传递闭包)

    N (1 ≤ N ≤ 100) cows, conveniently numbered 1-N, are participating in a programming contest. As we a ...

最新文章

  1. python预处理删除特殊字符_python - 如何删除包含特殊字符的字符串?_others_酷徒编程知识库...
  2. 数据结构的映像方法(数据元素的机内表示)
  3. 陈希孺院士带来开年第一本数学书,让人看完大呼过瘾的统计学科普读本
  4. winsock setsockopt 详解
  5. How to install Toad on linux with Corssover
  6. sparkshelljarlib_Spark应用程序第三方jar文件依赖解决方案
  7. 史上最全Java多线程面试题
  8. 没串口怎么操作核心板的Linux?ADB(以点灯为例)
  9. 离线搭建安卓环境 adt
  10. BackTrack 4 R2 发布
  11. Flask 个人网站重构上线
  12. Chrome浏览器书签手动同步
  13. Element-UI Select 下拉框 根据汉字拼音过滤选择选项(使用filter-method,filterable属性)
  14. Unity3D 关于材质球自发光_EmissionColor参数,构建后无法动态修改颜色值解决办法
  15. Python显示WiFi密码
  16. 链表A拆分成奇数和偶数值链表B和C
  17. vs2017无法解析外部符号__imp__fprintf和__imp____iob_func
  18. Node 学习 | Day03 express (初识Express、Express 路由、Express 中间件、使用 Express 写接口)
  19. 大哥無極的币圈沉浮史:从负债1亿到身家10亿
  20. 黑中介北京链家,收了中介费,不给你服务

热门文章

  1. C++编译代码的时候提示‘getInstance’ is not a member of ‘A’ A a = A::getInstance();解决办法
  2. linux之ls只显示文件或者文件夹
  3. Android之6.0上的重要变化(二)
  4. Android之React Native 中组件的生命周期
  5. Android之编程中存在性能影响的主要方面
  6. batchsize和数据量设置比例_Keras - GPU ID 和显存占用设定步骤
  7. java requestbody map_@RequestBody 的正确使用办法
  8. arraylist从大到小排序_经典排序方法的python实现和复杂度分析
  9. 培养沙雕要从娃娃抓起
  10. 一名毕业生的自述:我知道我必须写论文,但没聪明到可以写出来......