The Last Non-zero Digit POJ - 1150(n!mod p)

题意:

要求你求出n!(n−m)!)\frac{n!}{(n-m)!)}(nm)!)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)!)}(nm)!)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 ,题目分析简略,见谅,转载请注明出处。。。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309563.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Istio 1.6——迈向极简主义

从 1.2 版本开始&#xff0c;Istio 进入季度发布的节奏。5 月 21 日发布的 1.6 版本可以说是最准时的一次。我们是否可以理解 Istio 架构简化后的开发工作已经步入了正轨&#xff1f;这次的更新是否会带给我们惊喜&#xff1f;亦或是还有遗憾&#xff1f;让我们一一道来。&…

[Java基础]获取Class类的对象

代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Student(String …

使用PInvoke互操作,让C#和C++愉快的交互优势互补

一&#xff1a;背景1. 讲故事如果你常翻看FCL的源码&#xff0c;你会发现这里面有不少方法借助了C/C的力量让C#更快更强悍,如下所示&#xff1a;[DllImport("QCall", CharSet CharSet.Unicode)][SecurityCritical][SuppressUnmanagedCodeSecurity]private static ex…

[Java基础]反射获取构造方法并使用

代码如下: package ClassObjectPack;import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException;public class ReflectDemo01 {public static void main(String[] args) throws ClassNotFoundExcep…

题目 1886: [蓝桥杯][2017年第八届真题]包子凑数(欧几里得+完全背包)

题目&#xff1a; 时间限制: 1Sec 内存限制: 128MB 提交: 1049 解决: 365 题目描述 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有N种蒸笼&#xff0c;其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。 每当有顾客想买X…

[Java基础]反射获取构造方法并使用练习

Student类代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Studen…

Dotnet core使用JWT认证授权最佳实践(一)

最近&#xff0c;团队的小伙伴们在做项目时&#xff0c;需要用到JWT认证。遂根据自己的经验&#xff0c;整理成了这篇文章&#xff0c;用来帮助理清JWT认证的原理和代码编写操作。一、JWTJSON Web Token (JWT)是一个开放标准(RFC 7519)&#xff0c;它定义了一种紧凑的、自包含的…

[Java基础]反射获取成员变量并使用

代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Student(String …

2018年蓝桥杯B组题E题+快排

题目&#xff1a; E 快速排序&#xff1a;以下代码可以从数组a[]中找出第k小的元素。 它使用了类似快速排序中的分治算法&#xff0c;期望时间复杂度是O(N)的。 请仔细阅读分析源码&#xff0c;填写划线部分缺失的内容。 #include <stdio.h> int quick_select(int a[],…

Angular SPA基于Ocelot API网关与IdentityServer4的身份认证与授权

在上一讲中&#xff0c;我们已经完成了一个完整的案例&#xff0c;在这个案例中&#xff0c;我们可以通过Angular单页面应用&#xff08;SPA&#xff09;进行登录&#xff0c;然后通过后端的Ocelot API网关整合IdentityServer4完成身份认证。在本讲中&#xff0c;我们会讨论在当…

[Java基础]反射获取成员变量并使用练习

代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Student(String …

基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一)

上一篇文章使用AutoMapper来处理对象与对象之间的映射关系&#xff0c;本篇主要围绕定时任务和数据抓取相关的知识点并结合实际应用&#xff0c;在定时任务中循环处理爬虫任务抓取数据。开始之前可以删掉之前测试用的几个HelloWorld&#xff0c;没有什么实际意义&#xff0c;直…

题目 2285: [蓝桥杯][2018年第九届真题]螺旋折线(数论+思维)

题目&#xff1a; 题目描述 如图所示的螺旋折线经过平面上所有整点恰好一次。 对于整点(X, Y)&#xff0c;我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。 例如dis(0, 1)3, dis(-2, -1)9 给出整点坐标(X, Y)&#xff0c;你能计算出dis(X, Y)吗&…

[Java基础]反射获取成员方法并使用练习

代码如下: package ClassObjectPack;public class Student {private String name;int age;public String address;public Student(String name, int age, String address) {this.name name;this.age age;this.address address;}public Student() {}private Student(String …

读懂操作系统之虚拟内存(一)

由于个人对虚拟内存这块特别感兴趣&#xff0c;所以就直接暂且跳过其他&#xff0c;接下来将通过几篇文章进行详细讲解&#xff0c;当然其他基础内容后续在我进行相应整体学习后也会同步输出文章&#xff0c;比如操作系统概念、程序链接、进程管理、页面置换算法、流水线、浮点…

[Java基础]反射练习之越过泛型检查,运行配置文件制定内容

代码如下: package ReflectTest01;import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList;public class ReflectTest01 {public static void main(String[] args) throws NoSuchMethodException, InvocationTarg…

【Ids4实战】深究配置——用户信息操作篇

&#xff08;此花无日不春风&#xff09;其实IdentityServer4的小项目已经基本完结了&#xff0c;但是我总感觉还是有很多东西没有深入挖掘和研究的&#xff0c;这不&#xff0c;二群里有小伙伴问到了一个常见的问题&#xff0c;因为我去年都见到了&#xff0c;一直没有想过去解…

Sql Server之旅——第九站 看看DML操作对索引的影响

我们都知道建索引是需要谨慎的&#xff0c;当只有利大于弊的时候才适合建&#xff0c;同时也知道建索引是需要维护成本的&#xff0c;这个维护也就在于DML操作&#xff0c;下面具体看看到底DML对索引都有哪些内幕。。。。一&#xff1a;delete操作现在大家都已经知道索引是以B树…