SCU - 1115 阶乘

题目:

N的阶乘定义为:N!=N×(N-1)×……×2×1

请编写一个程序,输出N的阶乘的十进制表示中从最末一个非0位开始,

自低位向高位数的第M位。

其中:0<=N<=10000,1<=M<=5

例如:N=5,M=2,结果是1(5!=120)  N=8,M=3,结果为0(8!=40320)

输入:

第一行一个整数K (1<=K<=100),代表测试数据的个数;

接下来K行,每行两个整数N,M

输出:

输出K行,每行一个整数,即测试数据的结果。

样例:

输入:

2

5 2

8 3

输出:

1

0

这个题目的链接:点击打开链接

题目很简洁,但是很有意思啊。

首先,10000!太大,肯定是边乘边取模。

但是模多少呢?10000!的末尾的0的个数可是很多的,不可能先模一个很大的数,再数有多少个0。

这个题目,我认为必须先求出,n!末尾的0的个数d。

其实就是求d,使得5^d |  n! 成立但5^(d+1) |  n!不成立。

函数degree_in_fact就是专门干这个的,而且代码简单的可怕。

原理:

画一个n行n列的矩阵,第i(i从1到n)行第j(j从1到n)列表示i是否是p^j的倍数,是它的倍数就是1,不是就是0

其实远远不需要n列,但是我只是给出定理的证明,和空间效率无关。

下面考虑这个矩阵的和。

一方面,每一行的和表示的是i里面的p的次数,比如第p^3行,前面3个为1,后面的都是0,所以这一行的和为3,即p的次数。

所以矩阵的和是n!中p的次数。

另一方面,每一列的和是,从1到n有多少个数是p^j的倍数,所以答案为n/(p^j)

综上,n!中p的次数为n/p+n/(p^2)+n/(p^3)+......当j足够大时n/(p^j)=0

请注意,这个表达式是无法用递归来写的,因为这是整数的除法,不是实数的除法。

不过很巧的是,刚好有这么一个定理:

n/p^j/p=n/p^(j+1)

不要以为这个很显然,本文所有的除法都是整数的除法,也就是5/2会得到2,和实数的不同。

定理的证明:

假设右边的n/p^(j+1)=k,即k*p^(j+1)<=n<(k+1)*p^(j+1)

那么k*p<=n/p^j<(k+1)*p,那么k<=n/p^j/p<k+1

即n/p^j/p=k,证毕。

现在,表达式可以改写了,n!中p的次数为n/p+n/p/p+n/p/p/p+......

这个式子就可以用递归非常简单的写出来了。

degree_in_fact(n, 5)的值就是n!末尾的0的个数。

算出来0的个数为num之后,又要怎么做呢?

从1到n累乘,在乘之前,去掉num个2和num个5,剩下所有的数累乘,同时模100000即可。

这样就可以得到n!除掉后缀0之后的的最后5位

(这5位除了最后一位肯定不是0之外,都有可能是0,事实上还有可能都是0)

代码:

#include<iostream>
using namespace std;

int degree_in_fact(int m, int p)//求m!中素数p的次数
{
	if (m)return degree_in_fact(m / p, p) + m / p;
	return 0;
}

int main()
{
	int k, n, m;
	cin >> k;
	while (k--)
	{
		cin >> n >> m;
		int num = degree_in_fact(n, 5);
		int fact = 1;
		for (int i = 1; i <= n; i++)
		{
			int j = i;
			while (j % 2 == 0 && num)
			{
				j /= 2;
				num--;
			}
			while (j % 5 == 0)j /= 5;
			fact = fact*j % 100000;
		}
		m--;
		while (m--)fact /= 10;
		cout << fact % 10 << endl;
	}
	return 0;
}
时间: 2024-08-24 04:35:18

SCU - 1115 阶乘的相关文章

SCU - 1689 算阶乘(10000的阶乘)

题目: Description 求给定数的阶乘. 输入 第一行为测试数据的组数n,后面有n个测试数据.每组测试数据一行,为一个不超过10000的非负整数. 可以保证,最后运算结果以十进制表示不会超过36000位. 输出 对于每组测试数据,输出一行,即相应的阶乘. 输入示例 3 2 3 4 输出示例 2 6 24 用数组来自定义整数的存储.乘法.输出,把1个数按照每5位切开,存到1个数组里面. 代码: #include<iostream> #include<stdio.h> #inc

SCU - 2763 Factorial(任意阶乘中任意数的次数)

题目: Description Robby is a clever boy, he can do multiplication very quickly, even in base-2 (binary system), base-16 (hexadecimal system) or base-100000. Now he wants to challenge your computer, the task is quite simple: Given a positive integer N,

算法-计算阶乘n!末尾0的个数

算法逻辑转载自计算阶乘n!末尾0的个数: 问题描述    给定参数n(n为正整数),请计算n的阶乘n!末尾所含有"0"的个数.    例如,5!=120,其末尾所含有的"0"的个数为1:10!= 3628800,其末尾所含有的"0"的个数为2:20!= 2432902008176640000,其末尾所含有的"0"的个数为4. 计算公式    这里先给出其计算公式,后面给出推导过程.    令f(x)表示正整数x末尾所含有的&q

1003 阶乘后面0的数量

1003 阶乘后面0的数量 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 n的阶乘后面有多少个0? 6的阶乘 = 1*2*3*4*5*6 = 720,720后面有1个0. Input 一个数N(1 <= N <= 10^9) Output 输出0的数量 Input示例 5 Output示例 1其实只要循环除五就可以找到规律,其实也可以证明出来. 1 #include <iostream> 2 #include <cstdio> 3 #

高精度运算-阶乘累积求和

# include <stdio.h> # include <math.h> # define N 66 int main(){ int s[N] = {0}, a[N] = {0};// s累加和,a累积求阶乘 int i,j,k,n,digit=1; //digit代表的是数字的位数 scanf("%d",&n); a[0]=1; s[0]=1; if(n==1)// 如果是1,阶乘和就是1,直接输出 printf("%d",s[

关于阶乘

描述:给定两个数n,m,其中m是一个素数. 将n(0<=n<=2^31)的阶乘分解质因数,求其中有多少个m. 注:^为求幂符号. 输入: 第一行是一个整数s(0<s<=100),表示测试数据的组数 随后的s行, 每行有两个整数n,m. 输出: 输出m的个数 样例输入 3 100 5 16 2 1000000000 13 样例输出 24 15 83333329 当n,m体量很小的时候,用这个代码就可以AC: 1 #include <iostream> 2 using na

XDU1019 阶乘因子的个数

题意是让你求一个最小的N, 使得N!有M个0,N的阶乘中2的因子是远多于5的因子的个数, 因此我们统计出5的个数就知道其后面有几个0,对于一个数mid, mid!中5的因子的个数为mid/5 + mid/25 + mid/5^3 + ... 可以发现mid越大mid!中的5的个数越多, 因此我们可以二分答案, 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include <iost

阶乘的精确值

问题描述:输入不超过1000的正整数,输出n!=1*2*3*...*n的结果 1000!约等于4*10^2567 所以设置数组的最大范围为3000 并采用逆序表示 eg: 123000  因为是逆序 所以输出321 1.java import java.util.Arrays; import java.util.Scanner;/** * 阶乘的精确值 * @author NEU-2015 * */ public class Demo { public static void main(Stri

51nod 1435 位数阶乘

1435 位数阶乘 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 X是一个n位数的正整数 (x=a0a1...an−1) 现在定义 F(x)=∏i=0n−1(ai!)  , 比如F(135)=1!*3!*5!=720. 我们给定一个n位数的整数X(至少有一位数大于1,X中可能有前导0), 然后我们去找一个正整数(s)符合以下条件: 1.这个数尽可能大, 2.这个数中不能含有数字0或1. 3.F(s)=F(x)