阶乘

目录

一,阶乘(factorial)

二,阶乘的简单计算

Aizu 0019 Factorial

SCU 1689 算阶乘

HDU 1042 N!

NYOJ 28 大数阶乘

三,阶乘中任意数的次数

HDU 1124 Factorial

POJ 1401、SPOJ 11 Factorial

SGU 154 Factorial

力扣 172. 阶乘后的零

力扣 793. 阶乘函数后 K 个零

四,阶乘的素因子分解

LightOJ 1035 Intelligent Factorial Factorization

UVA 884 Factorial Factors

UVA 10856 Recover Factorial

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

五,阶乘中素因子次数问题升级版

SCU 1115 阶乘

CSU 1594 Factorials

六,斯特林公式

POJ 1423 Big Number

HDU 1018 Big Number

LightOJ 1045 Digits of Factorial

七,阶乘的其他计算

CSU 1781、NBUT 1643 阶乘除法

CodeForces 515C Drazil and Factorial

POJ 1775、FZU 1106 Sum of Factorials

LightOJ 1189  Sum of Factorials


一,阶乘(factorial)

n!=1×2×3×...×(n-1)×n

0!=1

阶乘的性质 数论_nameofcsdn的博客-CSDN博客

1,性质

2,证明素数无限

矛盾。

3,其他性质

二,阶乘的简单计算

Aizu 0019 Factorial

题目:

Description

Write a program which reads an integer n and prints the factorial of n. You can assume that n ≤ 20.

Input
An integer n (1 ≤ n ≤ 20) in a line.

Output
Print the factorial of n in a line.

Sample Input
5
Output for the Sample Input
120

超级水题

话说这个OJ好像是日本的吧。

代码:

#include<iostream>
using namespace std;
 
long long fac[21] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800,87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000 };
 
int main()
{
	int n;
	cin >> n;
	cout << fac[n] << endl;
	return 0;
}

SCU 1689 算阶乘

题目:

Description

求给定数的阶乘。

输入
    第一行为测试数据的组数n,后面有n个测试数据。每组测试数据一行,为一个不超过10000的非负整数。
    可以保证,最后运算结果以十进制表示不会超过36000位。

输出
    对于每组测试数据,输出一行,即相应的阶乘。

输入示例
3
2
3
4
输出示例
2
6
24

用数组来自定义整数的存储、乘法、输出,把1个数按照每5位切开,存到1个数组里面。

代码:

#include<iostream>
#include<stdio.h>
#include<iomanip>
using namespace std;
 
int list[1002][7201];
int l[11][7201];
 
void f(int n, int k)	//k从0到10
{
	for (int j = 1; j <= 7200; j++)l[0][j] = list[n][j];
	for (int i = 1; i <= k; i++)
	{
		for (int j = 1; j <= 7200; j++)l[i][j] = l[i - 1][j] * (10 * (n - 1) + i);
		int temp = 0;
		for (int j = 1; j <= 7200; j++)
		{
			l[i][j] += temp;
			temp = l[i][j] / 100000;
			l[i][j] %= 100000;
		}
	}
}
 
void build()
{
	for (int i =2; i <= 1001; i++)
	{
		f(i - 1, 10);
		for (int j = 1; j <= 7200; j++)list[i][j] = l[10][j];
	}
}
 
void out(int n)
{
	int k = n - n / 10 * 10;
	f(n / 10 + 1, k);
	bool flag = false;
	for (int j = 7200; j > 0; j--)
	{
		if (flag)printf("%05d", l[k][j]);
		else if (l[k][j])
		{
			printf("%d", l[k][j]);
			flag = true;
		}
	}
}
 
int main()
{
	int t, n;
	cin >> t;
	for (int j = 7200; j > 0; j--)list[1][j] = 0;
	list[1][1] = 1;
	build();
	while (t--)
	{
		cin >> n;
		out(n);
		cout << endl;
	}
	return 0;
}

这个代码AC了。440ms

虽然build算出了1到10000所有数的阶乘,但是只存了1001个。

我做了测试,测试内容很简单,如果n是10000就输出1,结果就不能AC了。也就是说,测试数据刚好是到10000的。

我用word统计了一下,10000!有35660位。所以只能通过稀疏存储来防止爆内存。

f中的参数k是0到9,f在2个地方被调用。

build中调用的f的参数k都是10,out中都是0到9,还是挺有意思的。

然而,用java来写就简单多了。

代码:
 

import java.util.*;
import java.math.BigInteger;
public class Main {

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int k=Integer.parseInt(cin.nextLine());
        while(k-->0)
        {
            int n=Integer.parseInt(cin.nextLine());
            BigInteger s=new BigInteger("1");
            for(int i=1;i<=n;i++)s=s.multiply(BigInteger.valueOf(i));
            System.out.println(s.toString());
        }
        
    }
}

HDU 1042 N!

题目:

Description

Given an integer N(0 ≤ N ≤ 10000), your task is to calculate N! 
Input

One N in one line, process to the end of file. 
Output

For each N, output N! in one line. 
Sample Input

1
2
3
Sample Output

1
2
6


JAVA大数真的好用。

import java.util.*;
import java.math.BigInteger;
public class Main {

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        while(cin.hasNext())
        {
            int n=Integer.parseInt(cin.nextLine());
            BigInteger s=new BigInteger("1");
            for(int i=1;i<=n;i++)s=s.multiply(BigInteger.valueOf(i));
            System.out.println(s.toString());
        }
        
    }
}

NYOJ 28 大数阶乘

题目:

大数阶乘
时间限制: 3000 ms  |  内存限制: 65535 KB
描述
我们都知道如何计算一个数的阶乘,可是,如果这个数很大呢,我们该如何去计算它并输出它?
输入
输入一个整数m(0<m<=5000)
输出
输出m的阶乘,并在输出结束之后输入一个换行符
样例输入
50
样例输出
30414093201713378043612608166064768844377641568960512000000000000
代码:

import java.util.*;
import java.math.BigInteger;
public class Main {
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n=Integer.parseInt(cin.nextLine());
        BigInteger s=new BigInteger("1");
        for(int i=1;i<=n;i++)s=s.multiply(BigInteger.valueOf(i));
        System.out.println(s.toString());
    }
}

三,阶乘中任意数的次数

f(n,p)=[\frac{n}{p}]+f([\frac{n}{p}],p)  

class Factorial:public Facs
{
public:
	static inline int degree(int m, int p)//求m!中素数p的次数
	{
		int ans = 0;
		while (m)ans += m / p, m /= p;
		return ans;
	}
	static inline int degree2(int m, int n)//求m!中n的次数
	{
		vector<pair<int, int>> vp = fenjie(n);
		int ans = degree(m, vp[0].first) / vp[0].second;
		for (int i = 1; i < vp.size(); i++)ans = min(ans, degree(m, vp[i].first) / vp[i].second);
		return ans;
	}
};

degree2需要因式分解,对于n=10的特例,degree2(m,10)== degree(m,5)恒成立。

所以实际上degree2可以做一些优化,减少degree的调用次数。

OJ实战: 

HDU 1124 Factorial

题目:
Description

The most important part of a GSM network is so called Base Transceiver Station (BTS). These transceivers form the areas called cells (this term gave the name to the cellular phone) and every phone connects to the BTS with the strongest signal (in a little simplified view). Of course, BTSes need some attention and technicians need to check their function periodically. 
ACM technicians faced a very interesting problem recently. Given a set of BTSes to visit, they needed to find the shortest path to visit all of the given points and return back to the central company building. Programmers have spent several months studying this problem but with no results. They were unable to find the solution fast enough. After a long time, one of the programmers found this problem in a conference article. Unfortunately, he found that the problem is so called "Travelling Salesman Problem" and it is very hard to solve. If we have N BTSes to be visited, we can visit them in any order, giving us N! possibilities to examine. The function expressing that number is called factorial and can be computed as a product 1.2.3.4....N. The number is very high even for a relatively small N. 

The programmers understood they had no chance to solve the problem. But because they have already received the research grant from the government, they needed to continue with their studies and produce at least some results. So they started to study behaviour of the factorial function. 

For example, they defined the function Z. For any positive integer N, Z(N) is the number of zeros at the end of the decimal form of number N!. They noticed that this function never decreases. If we have two numbers N1<N2, then Z(N1) <= Z(N2). It is because we can never "lose" any trailing zero by multiplying by any positive number. We can only get new and new zeros. The function Z is very interesting, so we need a computer program that can determine its value efficiently. 
Input

There is a single positive integer T on the first line of input. It stands for the number of numbers to follow. Then there is T lines, each containing exactly one positive integer number N, 1 <= N <= 1000000000. 
Output

For every number N, output a single line containing the single non-negative integer Z(N). 
Sample Input

6
3
60
100
1024
23456
8735373
Sample Output

0
14
24
253
5861
2183837

代码:

#include<iostream>
#include<string>
#include<string.h>
using namespace std;

int degree_in_fact(int m, int p)
{
	if (m)return degree_in_fact(m / p, p) + m / p;
	return 0;
}

int main()
{
	int t, n;
	cin >> t;
	while (t--)
	{
		cin >> n;
		cout << degree_in_fact(n, 5) << endl;
	}
	return 0;
}

POJ 1401、SPOJ 11 Factorial

题目:

Description

The most important part of a GSM network is so called Base Transceiver Station (BTS). These transceivers form the areas called cells (this term gave the name to the cellular phone) and every phone connects to the BTS with the strongest signal (in a little simplified view). Of course, BTSes need some attention and technicians need to check their function periodically.

ACM technicians faced a very interesting problem recently. Given a set of BTSes to visit, they needed to find the shortest path to visit all of the given points and return back to the central company building. Programmers have spent several months studying this problem but with no results. They were unable to find the solution fast enough. After a long time, one of the programmers found this problem in a conference article. Unfortunately, he found that the problem is so called "Travelling Salesman Problem" and it is very hard to solve. If we have N BTSes to be visited, we can visit them in any order, giving us N! possibilities to examine. The function expressing that number is called factorial and can be computed as a product 1.2.3.4....N. The number is very high even for a relatively small N.

The programmers understood they had no chance to solve the problem. But because they have already received the research grant from the government, they needed to continue with their studies and produce at least some results. So they started to study behaviour of the factorial function.

For example, they defined the function Z. For any positive integer N, Z(N) is the number of zeros at the end of the decimal form of number N!. They noticed that this function never decreases. If we have two numbers N1<N2, then Z(N1) <= Z(N2). It is because we can never "lose" any trailing zero by multiplying by any positive number. We can only get new and new zeros. The function Z is very interesting, so we need a computer program that can determine its value efficiently.

Input
There is a single positive integer T on the first line of input (equal to about 100000). It stands for the number of numbers to follow. Then there are T lines, each containing exactly one positive integer number N, 1 <= N <= 1000000000.

Output
For every number N, output a single line containing the single non-negative integer Z(N).

Example
Sample Input:

6
3
60
100
1024
23456
8735373
Sample Output:

0
14
24
253
5861
2183837
代码:

#include<iostream>
#include<string>
#include<string.h>
using namespace std;

int degree_in_fact(int m, int p)
{
	if (m)return degree_in_fact(m / p, p) + m / p;
	return 0;
}

int main()
{
	int t, n;
	cin >> t;
	while (t--)
	{
		cin >> n;
		cout << degree_in_fact(n, 5) << endl;
	}
	return 0;
}

SGU 154 Factorial

题目:

You task is to find minimal natural number N, so that N! contains exactly Q zeroes on the trail in decimal notation. As you know N! = 1*2*...*N. For example, 5! = 120, 120 contains one zero on the trail.

Input
One number Q written in the input (0<=Q<=10^8).

Output
Write "No solution", if there is no such number N, and N otherwise.

Sample test(s)

Input
2
Output
10

这个题目其实就是求,满足degree_in_fact(m,5)=q的最小m
但是因为q非常大,而m一定比q还大,所以m不能从1开始枚举,要先给m估值。

注意到,因为要求最小的m,所以m肯定是5的倍数。

假设m=k*5,那么 q=k+k/5+k/(5*5)+k/(5*5*5)+......<k*1.0/(1-1.0/5)=k*5/4.0

所以q*4<k*5,即k>=q*4/5+1

这个k就是我的代码中的key

代码:
 

#include<iostream>
using namespace std;
 
long long degree_in_fact(long long m, int p)
{
	if (m)return degree_in_fact(m / p, p) + m / p;
	return 0;
}
 
int main()
{
	long long q;
	cin >> q;
	if (q == 0)
	{
		cout << "1";
		return 0;
	}
	long long key = q * 4 / 5 + 1;
	while (degree_in_fact(key, 5) + key<q)key++;
	if (degree_in_fact(key, 5) + key == q)cout << key * 5;
	else cout << "No solution";
	return 0;
}

代码里面有q为0的特判,这是这个题目的污点。

如果没有这个特判的话,输入0会输出0,明明这个刚好符合要求,

而且所有输出的数字都是5的倍数,很好。偏偏这个题目非要这么破坏一下美感。。。

力扣 172. 阶乘后的零

给定一个整数 n ,返回 n! 结果中尾随零的数量。

提示 n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1

示例 1:

输入:n = 3
输出:0
解释:3! = 6 ,不含尾随 0

示例 2:

输入:n = 5
输出:1
解释:5! = 120 ,有一个尾随 0

示例 3:

输入:n = 0
输出:0

提示:

  • 0 <= n <= 104

进阶:你可以设计并实现对数时间复杂度的算法来解决此问题吗?

class Solution {
public:
    int degree_in_fact(int m, int p)
    {
        if (m)return degree_in_fact(m / p, p) + m / p;
        return 0;
    }
    int trailingZeroes(int n) {
        return degree_in_fact(n,5);
    }
};

rust代码:

impl Solution {
    pub fn trailing_zeroes(n: i32) -> i32 {
        if n == 0{
            return 0;
        }
        return n/5 + Solution::trailing_zeroes(n/5);
    }
}

力扣 793. 阶乘函数后 K 个零

 f(x) 是 x! 末尾是 0 的数量。回想一下 x! = 1 * 2 * 3 * ... * x,且 0! = 1 。

  • 例如, f(3) = 0 ,因为 3! = 6 的末尾没有 0 ;而 f(11) = 2 ,因为 11!= 39916800 末端有 2 个 0 。

给定 k,找出返回能满足 f(x) = k 的非负整数 x 的数量。

示例 1:

输入:k = 0
输出:5
解释:0!, 1!, 2!, 3!, 和 4! 均符合 k = 0 的条件。

示例 2:

输入:k = 5
输出:0
解释:没有匹配到这样的 x!,符合 k = 5 的条件。

示例 3:

输入: k = 3
输出: 5

提示:

  • 0 <= k <= 109
template<typename T>
class Bsearch { //寻找[low,high]中最小的满足isOk条件的数,low<=high,返回值范围是[low,high+getGap()]
public:
	T find(T low, T high)
	{
		if (!isOk(high))return high + getGap(high);
		if (isOk(low))return low;
		T mid;
		while (high - low > getGap(low)) {
			mid = (high + low) / 2;
			if (isOk(mid))high = mid;
			else low = mid;
		}
		return high;
	}
private:
	virtual bool isOk(T x) const //若isOk(x)且!isOk(y)则必有y<x,即isOk表示足够大
	{
		return 0;
	}
	int getGap(int) {
		return 1;
	}
	int getGap(long long) {
		return 1;
	}
	double getGap(double) {
		return 0.00000001;
	}
};

long long degree_in_fact(long long m, int p)
{
	if (m)return degree_in_fact(m / p, p) + m / p;
	return 0;
}
class Find1 :public Bsearch<long long>
{
public:
	Find1(int nn) :n{ nn } {};
private:
	virtual bool isOk(long long x) const //若isOk(x)且!isOk(y)则必有y<x,即isOk表示足够大
	{
		return degree_in_fact(x, 5) >= n;
	}
	int n;
};
class Find2 :public Bsearch<long long>
{
public:
	Find2(int nn) :n{ nn } {};
private:
	virtual bool isOk(long long x) const //若isOk(x)且!isOk(y)则必有y<x,即isOk表示足够大
	{
		return degree_in_fact(x, 5) > n;
	}
	int n;
};

class Solution {
public:
	int preimageSizeFZF(long long k) {
		return Find2(k).find(0, k * 10+10) - Find1(k).find(0, k * 10 + 10);
	}
};

rust代码:


trait Search{
    fn find(&self,low:i64,high:i64)-> i64;
    fn check_value(&self,x:i64)->bool;
    fn trailing_zeroes(&self,n:i64)->i64;
}
struct SearchData{
    target:i64
}
impl Search for SearchData{
    fn find(&self, low:i64,high:i64)-> i64{
        let mut low = low;
        let mut high = high;
        if self.check_value(high) == false{
            return high+1;
        }
        if self.check_value(low) == true{
            return low;
        }
        while high - low > 1 {
            let mid = (high + low)/2;
            if self.check_value(mid) == true{
                high = mid;
            }
            else {
                low = mid;
            }
        }
        return high;
    }
    fn check_value(&self,x:i64)->bool{
        return self.trailing_zeroes(x)>self.target;
    }
    fn trailing_zeroes(&self,n: i64) -> i64 {
        if n == 0{
            return 0;
        }
        return n/5 + Search::trailing_zeroes(self,n/5);
    }
}

impl Solution {
    pub fn preimage_size_fzf(k: i32) -> i32 {
        let k:i64=k as i64;
        let opt=SearchData{target:k};
        let high = opt.find(0, k*10+10);
        let k = k-1;
        let opt=SearchData{target:k};
        let low = opt.find(0, k*10+10);
        let ans=(high-low) as i32;
        return ans;
    }
}

四,阶乘的素因子分解

n!中的素因子,刚好就是2到n中所有的素数。

	static vector<pair<int, int>> factorization(int n) //求n!的因式分解
	{
		vector<pair<int, int>> vp;
		for (auto i : GetSingleA().getPrime(n)) {
			if (i > n)break;
			vp.push_back({ i, degree(n,i) });
		}
		return vp;
	}

LightOJ 1035 Intelligent Factorial Factorization

题目:

Description

Given an integer N, you have to prime factorize N! (factorial N).

Input

Input starts with an integer T (≤ 125), denoting the number of test cases.

Each case contains an integer N (2 ≤ N ≤ 100).

Output

For each case, print the case number and the factorization of the factorial in the following format as given in samples.

Case x: N = p1 (power of p1) * p2 (power of p2) * ...

Here x is the case number, p1, p2 ... are primes in ascending order.

Sample Input

3

2

3

6

Sample Output

Case 1: 2 = 2 (1)

Case 2: 3 = 2 (1) * 3 (1)

Case 3: 6 = 2 (4) * 3 (2) * 5 (1)

题意:输出阶乘的素因子分解

首先要分析哪些素数会输出。

结论是很简单的,不超过n的素数都会输出,超过n的都不会输出。

而且,2一定在里面,也就是说,2一定是第一个,这样就很方便了。

代码:

#include<iostream>
#include<stdio.h>
using namespace std;

#define FactorialFactorization Factorial::factorization //求n!的因式分解

int main()
{
	int t, n;
	cin >> t;
	for (int cas = 1; cas <= t; cas++)
	{
		cin >> n;
		auto vp = FactorialFactorization(n);
		cout << "Case " << cas << ": " << n << " = 2 (" << vp[0].second << ")";
		for (int i = 1; i <vp.size(); i ++)
			cout << " * " << vp[i].first << " (" << vp[i].second << ")";
		cout << endl;
	}
	return 0;
}

UVA 884 Factorial Factors

题目:

这个题目就是求n!的素因子的总个数(计重数)

代码:

#include<iostream>
using namespace std;

#define FactorialFactorization Factorial::factorization //求n!的因式分解

int main()
{
	int n;
	while (cin >> n)
	{
		int s = 0;
		auto vp = FactorialFactorization(n);
		for (auto vi : vp)s += vi.second;
		cout << s << endl;
	}
	return 0;
}

UVA 10856 Recover Factorial

题目:(Sample Output是错的!要不是因为题目里面有描述输出,估计没人做的对吧)

这个题目和UVA - 884 Factorial Factors有着紧密的联系,

用到了二分,可以确定,需要的数组大小的大致范围,大于2700000,小与2750000

代码:

#include<iostream>
using namespace std;

int sum[2750000];

bool isprime(int n)
{
	if (n == 2)return true;
	if (n % 2 == 0)return false;
	for (int i = 3; i*i <= n; i += 2)if (n%i == 0)return false;
	return true;
}

int main()
{
	for (int i = 0; i < 2750000; i++)sum[i] = 0;
	for (int i = 2; i < 2750000; i++)
	{
		if (isprime(i))
		{
			long long m = i;
			while (m < 2750000)
			{
				for (int j = m; j < 2750000; j += m)sum[j]++;
				m *= i;
			}
		}
	}
	for (int i = 1; i < 2750000; i++)sum[i] += sum[i - 1];
	int n, low, high, mid;
	int cas = 1;
	while (cin >> n)
	{
		if (n < 0)break;
		cout << "Case " << cas++ << ": ";
		low = 0, high = 2749999;
		while (low < high - 1)
		{
			mid = (low + high) / 2;
			if (sum[mid] < n)low = mid;
			else if (sum[mid]>n)high = mid;
			else break;
		}
		if (n == 0)mid = 0;
		if (sum[mid] == n)cout << mid << "!\n";
		else cout << "Not possible.\n";
	}
	return 0;
}

在查找的时候,还是二分,因为数组已经是升序的了。

不过,有个特殊情况,sum[0]=sum[1]=0,这是唯一的不是严格递增的地方,需要特判。

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, if we express the N ! (N ! = N * (N - 1) * (N - 2) * ... * 2 * 1) 
in base-B, how many ZEROs there will be at the end of the number. Can you make a wonderful program to beat him?
Input
Each test case contain one line with two numbers N and B. (1 ≤ N ≤ 10^9, 2 ≤ B ≤ 100000)
The input is terminated with N = B = 0. 

Output
Output one line for each test case, indicating the number of ZEROs.

Sample Input
7 10
7 10000
7 2
0 0

Sample Output
1
0
4

题目的意思就是,任给2个整数n、b,要求n!的b进制表示中有多少个后缀0,即求满足b^k整除n!的最大整数k

代码:

#include<iostream>
using namespace std;

#define FactorialDegree2 Factorial::degree2 //求m!中n的次数

int main()
{
	int k = 0;
	int n, b;
	while (cin >> n >> b)
	{
		if (b == 0)break;
		cout << FactorialDegree2(n, b) << endl;
	}
	return 0;
}

五,阶乘中素因子次数问题升级版

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

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

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

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

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

代码:

#include<iostream>
using namespace std;

int main()
{
	int k, n, m;
	cin >> k;
	while (k--)
	{
		cin >> n >> m;
		auto vp = FactorialFactorization(n);
		int s5 = vp.size() >= 3 ? vp[2].second : 0;
		int fact = 1;
		for (auto vi : vp) {
			if (vi.first == 5)continue;
			if(vi.first==2)vi.second -= s5;
			for (int i = 0; i < vi.second; i++)fact = fact * vi.first % 100000;
		}
		while (--m)fact /= 10;
		cout << fact % 10 << endl;
	}
	return 0;
}

CSU 1594 Factorials

题目:

Description

The factorial of an integer N, written N!, is the product of all the integers from 1 through N inclusive. The factorial quickly becomes very large: 13! is too large to store in a 32-bit integer on most computers, and 70! is too large for most floating-point variables. Your task is to find the rightmost non-zero digit of n!. For example, 5! = 1 * 2 * 3 * 4 * 5 = 120, so the rightmost non-zero digit of 5! is 2. Likewise, 7! = 1 * 2 * 3 * 4 * 5 * 6 * 7 = 5040, so the rightmost non-zero digit of 7! is 4.

Input

This problem includes multiple cases. The first line of input is a integer T represents the number of cases. 
For each case, there is a single positive integer N no larger than 4,220.

Output

For each case, output corresponding results separately.
The output of each case is a single line containing but a single digit: the right most non-zero digit of N!.

Sample Input

1
7
Sample Output

4

SCU - 1115 阶乘是这个题目的直接推广,我先做了那个题目,所以这个题目秒了。

代码:

#include<iostream>
using namespace std;

int main()
{
	int k, n;
	cin >> k;
	while (k--)
	{
		cin >> n;
		auto vp = FactorialFactorization(n);
		int s5 = vp.size() >= 3 ? vp[2].second : 0;
		int fact = 1;
		for (auto vi : vp) {
			if (vi.first == 5)continue;
			if(vi.first==2)vi.second -= s5;
			for (int i = 0; i < vi.second; i++)fact = fact * vi.first % 10;
		}
		cout << fact << endl;
	}
	return 0;
}

六,斯特林公式

斯特林公式 数论_nameofcsdn的博客-CSDN博客

POJ 1423 Big Number

题目:
Description

In many applications very large integers numbers are required. Some of these applications are using keys for secure transmission of data, encryption, etc. In this problem you are given a number, you have to determine the number of digits in the factorial of the number.
Input

Input consists of several lines of integer numbers. The first line contains an integer n, which is the number of cases to be tested, followed by n lines, one integer 1 <= m <= 10^7 on each line.
Output

The output contains the number of digits in the factorial of the integers appearing in the input.
Sample Input

2
10
20
Sample Output

7
19
代码:

#include<iostream>
#include<cmath>
using namespace std;

int main()
{
	int t, n;
	cin >> t;
	while (t--)
	{
		cin >> n;
		cout << int(log10(2 * acos(-1.0)*n) / 2 + (log10(n) - 1 / log(10))*n + 1 / log(10) / n / 12)+1<<endl;
	}
	return 0;
}

HDU 1018 Big Number

题目:
Description

In many applications very large integers numbers are required. Some of these applications are using keys for secure transmission of data, encryption, etc. In this problem you are given a number, you have to determine the number of digits in the factorial of the number. 
Input

Input consists of several lines of integer numbers. The first line contains an integer n, which is the number of cases to be tested, followed by n lines, one integer 1 ≤ n ≤ 10 7 on each line. 
Output

The output contains the number of digits in the factorial of the integers appearing in the input. 
Sample Input

2
10
20
Sample Output

7
19
代码:

#include<iostream>
#include<cmath>
using namespace std;

int main()
{
	int t, n;
	cin >> t;
	while (t--)
	{
		cin >> n;
		cout << int(log10(2 * acos(-1.0)*n) / 2 + (log10(n) - 1 / log(10))*n + 1 / log(10) / n / 12)+1<<endl;
	}
	return 0;
}

LightOJ 1045 Digits of Factorial

题目:

Description

Factorial of an integer is defined by the following function

f(0) = 1

f(n) = f(n - 1) * n, if(n > 0)

So, factorial of 5 is 120. But in different bases, the factorial may be different. For example, factorial of 5 in base 8 is 170.

In this problem, you have to find the number of digit(s) of the factorial of an integer in a certain base.

Input

Input starts with an integer T (≤ 50000), denoting the number of test cases.

Each case begins with two integers n (0 ≤ n ≤ 106) and base (2 ≤ base ≤ 1000). Both of these integers will be given in decimal.

Output

For each case of input you have to print the case number and the digit(s) of factorial n in the given base.

Sample Input

5

5 10

8 10

22 3

1000000 2

0 100

Sample Output

Case 1: 3

Case 2: 5

Case 3: 45

Case 4: 18488885

Case 5: 1

因为T很大,N也很大,所以要用数组存结果,然后不停调用。

#include<iostream>
#include<stdio.h>
#include<cmath>
using namespace std;
 
double logg[1000001];
 
int main()
{
	int t, n, base;
	cin >> t;
	logg[0] = 0;
	for (int i = 1; i < 1000001; i++)logg[i] += logg[i - 1] + log(i);
	for (int i = 1; i <= t; i++)
	{
		scanf("%d%d", &n, &base);
		printf("Case %d: %d\n", i, int(logg[n]/log(base)) + 1);
	}
	return 0;
}

没有考虑logg[n]/log(base)刚好是整数的情况,这个地方可以优化一下。

这个题目,如果用斯特林公式做的话,更快。

七,阶乘的其他计算

CSU 1781、NBUT 1643 阶乘除法

题目:
Description

输入两个正整数 n, m,输出 n!/m!,其中阶乘定义为 n!= 1*2*3*...*n (n>=1)。 比如,若 n=6, m=3,则n!/m!=6!/3!=720/6=120。

是不是很简单?现在让我们把问题反过来:输入 k=n!/m!,找到这样的整数二元组(n,m) (n>m>=1)。

如果答案不唯一,n 应该尽量小。比如,若 k=120,输出应该是 n=5, m=1,而不是 n=6, m=3,因为 5!/1!=6!/3!=120,而5<6。

Input

输入包含不超过 100 组数据。每组数据包含一个整数 k (1<=k<=10^9)。
Output

对于每组数据,输出两个正整数 n 和 m。无解输出"Impossible",多解时应让 n 尽量小。
Sample Input

120
1
210
Sample Output

Case 1: 5 1
Case 2: Impossible
Case 3: 7 4

这个题目,我加了一个数组list,记录了从0到11的阶乘。

用这个可以减少一些运算,因为如果k=n!/m!,那么一定有(n-m)! | k

代码:

#include<iostream>
#include<stdio.h>
using namespace std;

int list[12] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800 };

bool ok(int n, int k,int l)
{
	long long r = l;
	for (int i = 1; i < k; i++)
	{
		r *= l + i;
		if (r>n)return false;
	}
	return true;
}

int f(int n, int k)
{
	if (n%list[k])return -1;
	long long low = 2, high = n / 2;
	while (low < high-1)
	{
		int mid = (low + high) / 2;
		if (ok(n, k, mid))low = mid;
		else high = mid;
	}
	int r = low;
	for (int i = 1; i < k; i++)r *= low + i;
	if (r == n)return low;
	return -1;
}

int main()
{
	int cas = 1;
	int n;
	while (scanf("%d",&n)!=EOF)
	{
		cout << "Case " << cas++ << ": ";
		if (n == 1)cout << "Impossible";
		else
		{
			int r = 1234567890, key = 0;
			for (int k = 2; k <= 11; k++)
			{
				int t = f(n, k);
				if (t>0 && r > t)
				{
					r = t;
					key = k;
				}
			}
			if (r < 1234567890)cout << key + r - 1 << " " << r - 1;
			else cout << n << " " << n - 1;
		}
		cout << endl;
	}
	return 0;
}

今天又遇到这个题目了,只好又写了一遍。

代码:

#include<iostream>
using namespace std;
 
int fac[13] = { 0,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600 };
int n, m, k;
 
bool ok(int low, int len)
{
	long long pi = 1;
	for (int i = 0; i < len; i++)
	{
		pi *= low + i;
		if (pi > k)return false;
	}
	return true;
}
 
void f()
{
	n = k;
	m = k - 1;
	for (int i = 2; i <= 12; i++)
	{
		if (k%fac[i])return;
		int low = 2, high = k, mid;
		while (low < high-1)
		{
			mid = (low + high) / 2;
			if (ok(mid, i))low = mid;
			else high = mid;
		}
		int pi = 1;
		for (int j = 0; j < i; j++)pi *= low + j;
		if (pi == k)
		{
			n = low + i - 1;
			m = low - 1;
		}
	}
}
 
int main()
{
	int cas = 1;
	while (cin >> k)
	{
		cout << "Case " << cas++ << ": ";
		if (k == 1)
		{
			cout << "Impossible" << endl;
			continue;
		}
		f();
		cout << n << " " << m << endl;
	}
	return 0;
}

CodeForces 515C Drazil and Factorial

题目:

Description

Drazil is playing a math game with Varda.

Let's define  for positive integer x as a product of factorials of its digits. For example, F(135)=1!*3!*5!

First, they choose a decimal number a consisting of n digits that contains at least one digit larger than 1. This number may possibly start with leading zeroes. Then they should find maximum positive number x satisfying following two conditions:

1. x doesn't contain neither digit 0 nor digit 1.

2. F(x)=F(a)

Help friends find such number.

Input

The first line contains an integer n (1 ≤ n ≤ 15) — the number of digits in a.

The second line contains n digits of a. There is at least one digit in a that is larger than 1. Number a may possibly contain leading zeroes.

Output

Output a maximum possible integer satisfying the conditions above. There should be no zeroes and ones in this number decimal representation.

Sample Input

Input
4
1234

Output

33222

Input

3
555

Output

555

这个题目其实就是全部替换成2/3/5/7,然后按照从大到小的顺序全部输出即可

代码:

#include<iostream>
using namespace std;
 
int main()
{
	int n;
	cin >> n;
	char c;
	int n2 = 0, n3 = 0, n5 = 0, n7 = 0;
	while (n--)
	{
		cin >> c;
		if (c == '2')n2++;
		if (c == '3')n3++;
		if (c == '4')
		{
			n3++;
			n2 += 2;
		}
		if (c == '5')n5++;
		if (c == '6')
		{
			n3++;
			n5++;
		}
		if (c == '7')n7++;
		if (c == '8')
		{
			n7++;
			n2 += 3;
		}
		if (c == '9')
		{
			n7++;
			n2++;
			n3 += 2;
		}
	}
	while (n7--)cout << '7';
	while (n5--)cout << '5';
	while (n3--)cout << '3';
	while (n2--)cout << '2';
	cout << endl;
	return 0;
}

为什么是2/3/5/7呢,因为它们是素数。

也就是说,5的倍数的最小阶乘就是5!等等。。

POJ 1775、FZU 1106 Sum of Factorials

题目:
Description

John von Neumann, b. Dec. 28, 1903, d. Feb. 8, 1957, was a Hungarian-American mathematician who made important contributions to the foundations of mathematics, logic, quantum physics,meteorology, science, computers, and game theory. He was noted for a phenomenal memory and the speed with which he absorbed ideas and solved problems. In 1925 he received a B.S. diploma in chemical engineering from Zurich Institute and in 1926 a Ph.D. in mathematics from the University of Budapest. His Ph.D. dissertation on set theory was an important contribution to the subject. At the age of 20, von Neumann proposed a new definition of ordinal numbers that was universally adopted. While still in his twenties, he made many contributions in both pure and applied mathematics that established him as a mathematician of unusual depth. His Mathematical Foundations of Quantum Mechanics (1932) built a solid framework for the new scientific discipline. During this time he also proved the mini-max theorem of GAME THEORY. He gradually expanded his work in game theory, and with coauthor Oskar Morgenstern he wrote Theory of Games and Economic Behavior (1944). 
There are some numbers which can be expressed by the sum of factorials. For example 9,9=1!+2!+3! Dr. von Neumann was very interested in such numbers. So, he gives you a number n, and wants you to tell him whether or not the number can be expressed by the sum of some factorials. 
Well, it's just a piece of cake. For a given n, you'll check if there are some xi, and let n equal to Σ  1<=i<=tx  i!. (t >=1 , xi >= 0, xi = xj iff. i = j). If the answer is yes, say "YES"; otherwise, print out "NO".
Input

You will get several non-negative integer n (n <= 1,000,000) from input file. Each one is in a line by itself. 
The input is terminated by a line with a negative integer.
Output

For each n, you should print exactly one word ("YES" or "NO") in a single line. No extra spaces are allowed.
Sample Input

9
-1
Sample Output

YES

这个题目是考1个性质:

当n>1时,0!+1!+2!+......+n!<(n+1)!,当n=1时,0!+1!=2!,当n=0时,0!=1!

任取一个递增的函数f(x)满足下述条件:当x为整数时,f(x)=x!

用g表示f的反函数,那么这个算法的时间复杂度为θ(g(n))

比如说,本题n约为10!,那么大约有10次运算

(我这个描述其实是不准确的,因为有常数的问题。

准确的说法应该是,这个算法有大约g(n)次运算,常数为1)

代码:
 

#include<iostream>
using namespace std;

int fac[10] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };

int main()
{
	int n;
	while (cin >> n)
	{
		if (n < 0)break;
		if (n == 0)cout << "NO";
		else
		{
			for (int i = 9; i >= 0; i--)if (n>=fac[i])n -= fac[i];
			if (n == 0)cout << "YES";
			else cout << "NO";
		}
		cout << endl;
	}
	return 0;
}

LightOJ 1189  Sum of Factorials

题目:

Description

Given an integer n, you have to find whether it can be expressed as summation of factorials. For given n, you have to report a solution such that

n = x1! + x2! + ... + xn! (xi < xj for all i < j)

Input

Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 1018).

Output

For each case, print the case number and the solution in summation of factorial form. If there is no solution then print 'impossible'. There can be multiple solutions, any valid one will do. See the samples for exact formatting.

Sample Input

4

7

7

9

11

Sample Output

Case 1: 1!+3!

Case 2: 0!+3!

Case 3: 1!+2!+3!

Case 4: impossible

题目差不多,代码稍微改下就可以了。

代码:

#include<iostream>
#include<stack>
using namespace std;
 
long long fac[20] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800,87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000 };
stack<int>s;
 
int main()
{
	int t;
	cin >> t;
	long long n;
	for (int cas = 1; cas <= t; cas++)
	{		
		cin >> n;
		cout << "Case " << cas << ": ";
		while (!s.empty())s.pop();
		for (int i = 19; i >= 0; i--)if (n >= fac[i])
		{
			n -= fac[i];
			s.push(i);
		}
		if (n == 0)
		{
			while (!s.empty())
			{
				n = s.top();
				s.pop();
				cout << n << '!';
				if (!s.empty())cout << '+';
			}
		}
		else cout << "impossible";
		cout << endl;		
	}	
	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值