BZOJ 3000(Big Number-Stirling公式求n!近似值)

3000: Big Number

Time Limit: 2 Sec  Memory Limit: 128 MB

Submit: 220  Solved: 62

[Submit][Status]

Description

给你两个整数N和K,要求你输出N!的K进制的位数。

Input

有多组输入数据,每组输入数据各一行,每行两个数——N,K

Output

每行一个数为输出结果。

Sample Input

2 5

2 10

10 10

100 200

Sample Output

1

1

7

69

对于100%的数据,有2≤N≤2^31, 2≤K≤200,数据组数T≤200。

HINT

Source

本题需要用到Stirling公式

∴位数=log10(n!)+1

方案1:[WA]n!不断div k

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
typedef long double ld;
ld log(ll a,int b){}
int main()
{
//	freopen("bzoj3000.in","r",stdin);
//	freopen(".out","w",stdout);
	ll n;int k;
	while (scanf("%lld%d",&n,&k)!=EOF)
	{
		if (n<=10000)
		{
			ll ans=0,p=1;
			Fork(i,2,n)
			{
				p*=i;
				while (p>=k) {p/=k,ans++;}
				cout<<i<<':'<<p<<' '<<ans<<endl;
			}
			if (p) ans++;
			printf("%lld\n",ans);
		}
	}

	return 0;
}

但是这样做是错的。TNT

理由是不断div k 会把原来小的部分删掉

方案2:logk(n!)=log(1)+log(2)+...+log(n)

效率为O(n),显然也不行

于是不妨用Stirling公式求近似值

位数=logk(n!)+1

≈ logk(sqrt(2πn)*(n/e)^n+1

= logk(sqrt(2πn))+log[(n/e)^n]+1

=1/2*logk(2πn)+nlog(n/e)+1

=0.5*logk(2πn)+nlog(n/e)+1

=0.5*logk(2πn)+nlog(n)-nlog(e)+1

PS:pi=acos(-1.0),e=exp(1)

PS2:eps的存在是为了防止n=2,k=2这样刚好的情况出现,这个时候向上取整要多取1位

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
typedef long double ld;
ld const pi=acos(-1.0),e=exp(1),eps=1e-10;
ld log(ld a,ld b){return log(a)/log(b);}
int main()
{
//	freopen("bzoj3000.in","r",stdin);
//	freopen(".out","w",stdout);
	ll n;int k;
	cout.setf(ios::fixed);
	cout.precision(0);

	while (scanf("%lld%d",&n,&k)!=EOF)
	{
		if (n<=10000)
		{
			ld ans=0.0;
			For(i,n) ans+=log(i);
			ans/=log(k);
			ans=ceil(ans+eps);
			cout<<ans<<endl;
		}
		else
		{
			cout<<ll(0.5*log(2*pi*n,k)+n*log(n,k)-n*log(e,k))+1<<endl;
		}

	}

	return 0;
}

BZOJ 3000(Big Number-Stirling公式求n!近似值),布布扣,bubuko.com

时间: 2024-10-16 09:10:32

BZOJ 3000(Big Number-Stirling公式求n!近似值)的相关文章

HDU 1018 -- Big Number (Stirling公式求n!的位数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1018 Big Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 40551    Accepted Submission(s): 19817 Problem Description In many applications ver

【c语言】用π/4 ≈ 1 - 1/3 + 1/5 - 1/7 +... 公式求π的近似值,直到发现某一项的绝对值小于10^6为止。

// 用π/4 ≈ 1 - 1/3 + 1/5 - 1/7 +... 公式求π的近似值,直到发现某一项的绝对值小于10^6为止. #include <stdio.h> #include <math.h> int main() { double sign = 1.0; int i; double sum = 0.0; for(i = 1;fabs(i) < pow( 10,6 ); i = i + 2) { sum = sum + sign / i; sign = ( -1 )

BZOJ 3000 Big Number 数学算法

题目大意:求n!在k进制下的位数 即 Stirling公式: 数据范围小就暴力,数据范围大套用Stirling公式 注意先利用log来避免数字过大而失精 最后答案要开long long #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const double pi=

BZOJ 3000: Big Number (数学)

题目: https://www.lydsy.com/JudgeOnline/problem.php?id=3000 题解: 首先n很大,O(n)跑不过,那么就要用一些高端 而且没听过 的东西——stirling公式 shirling公式:   n!≍√(2πn)*(n/e)^n 这个公式对于n很大的解还是有很高的准确度的,但是对于n比较小的情况就会有误差. 所以对于n很小就暴力. 注意用log的一堆公式: lg(a*b)=lg(a)+lg(b):lg(a/b)=lg(a)-lg(b); lg (

下列给定程序中函数fun的功能是:用下面的公式求π的近似值,直到最后一项的绝对值小于指定的数为止,π/4=1-1/3+1/5-1/7+...,例如,程序运行后,输入0.0001,程序输出3.1414

#include <math.h> #include <stdio.h> float fun ( float num ) { int s ; float n, t, pi ; t = 1 ; pi = 0 ; n = 1 ; s = 1 ; /**************found**************/ while(fabs(t) >= num) { pi = pi + t ; n = n + 2 ; s = -s ; /**************found****

【蓝桥杯】历届试题 公式求值

  历届试题 公式求值   时间限制:1.0s   内存限制:256.0MB 问题描述 输入n, m, k,输出下面公式的值. 其中C_n^m是组合数,表示在n个人的集合中选出m个人组成一个集合的方案数.组合数的计算公式如下. 输入格式 输入的第一行包含一个整数n:第二行包含一个整数m,第三行包含一个整数k. 输出格式 计算上面公式的值,由于答案非常大,请输出这个值除以999101的余数. 样例输入 313 样例输出 162 样例输入 201010 样例输出 359316 数据规模和约定 对于1

Stirling公式

n!与    的值十分接近,利用Stirling公式将阶乘转化成幂函数,使得阶乘的结果得以更好的估计.而且n越大,估计得就越准确 用该公式计算n!结果的位数时,可以两边取对数,得: #include<iostream> #include<math.h> using namespace std; const double e=2.7182818284590452354,pi=3.141592653589793239; //e和i的值要精确 double str_ling(int n)

蓝桥杯-历届试题-公式求值

历届试题 公式求值 时间限制:1.0s   内存限制:256.0MB 问题描述 输入n, m, k,输出下面公式的值. 其中C_n^m是组合数,表示在n个人的集合中选出m个人组成一个集合的方案数.组合数的计算公式如下. 输入格式 输入的第一行包含一个整数n:第二行包含一个整数m,第三行包含一个整数k. 输出格式 计算上面公式的值,由于答案非常大,请输出这个值除以999101的余数. 样例输入 313 样例输出 162 样例输入 201010 样例输出 359316 数据规模和约定 对于10%的数

复合梯形公式与复合辛普森公式求积分

一 实验目的 1. 掌握复合梯形公式与复合辛普森公式的基本思想.2. 编程实现用复合梯形公式与复合辛普森公式求积分.3. 熟悉matlab软件的使用. 二 实验内容1.用复合梯形公式计算积分 I=4/(1+x2)dx ,求它0到1的积分.精确度为10-5.(0.00001),精确到 ●1 计算公式 h=(b-a)/n h=h/2[(f(x0)+f(x1))+(f(x1)+f(x2))+(f(x2)+f(x3)+...+(f(xn-1)+f(xn)] l1 算法分析 En=h2/12[f'(b)-