N!的最高位

sanguine1211 2011-07-14 06:15:51
Time Limit:1000MS Memory Limit:30000KB
Total Submit:892 Accepted:153

Description

求N的阶乘的最高位数。
例如:
5!=120,所以最高位为1
10!=3628800,所以最高位为3

Input

每个数据包含一行,每行有一个整数N(0<=N<=10000000)

Output

对于每个测试数据,输出N!的最高位数字

Sample Input

5
10

Sample Output

1
3

Source

EOJ


代码验证:http://acm.cs.ecnu.edu.cn/problem.php?problemid=1007



求解各位大牛肿么做啊!!!
...全文
577 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
sanguine1211 2011-07-17
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 pathuang68 的回复:]

C/C++ code

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial = 0.0;
do
{
……
[/Quote]

这个方法我已经知道了,我想问下有木有什么方法不要后面的枚举啊……我一个学长他好像就是5行代码就AC了,他没有后面的枚举一些情况
sanguine1211 2011-07-17
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 uniqueroy 的回复:]

引用 23 楼 pathuang68 的回复:

C/C++ code

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial ……
[/Quote]


13行的,13第一位是6矣……只有这几位有问题……

有木有什么办法不要枚举后面的啊……
pathuang68 2011-07-17
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 uniqueroy 的回复:]

引用 23 楼 pathuang68 的回复:

C/C++ code

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial ……
[/Quote]
上面的代码计算13!的第一位数是6,实际上13!的阶乘的第一位数的确是6。没有问题。
pathuang68 2011-07-17
  • 打赏
  • 举报
回复
你学长的做法估计是下面这样的:

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

int main(int argc, char *argv[])
{
int n = 0, firstnumber = 0;
double log_n_factorial = 0.0;
do
{
cin >> n;

for(int i = 1; i <= n; ++i)
{
log_n_factorial += log((double)i) / log(10.0);
}
log_n_factorial -= (int)log_n_factorial;

firstnumber = exp(log_n_factorial * log(10.0));

cout << firstnumber << endl;

log_n_factorial = 0.0;

}while(n != 0); // n = 0时退出循环

return 0;
}


注意:
1. n = 0时应该输出1,这个在上面的程序中增加一个判断语句即可。因为0!是数学上的定义,无法计算。
2. 上面的算法速度也很快,不管n多小或者多大,得到的结果都肯定是精确值,这和Sterling公式在n较小时存在比较大的误差,是有区别的。折中算法的效率应该可以Accepted。
3. 在计算很大的n时,上面的算法速度应该不如用Sterling公式
4. 所以可以进行折中,在计算较小的n时,可以用上面的办法,计算较大的n时,用Sterling公式。即综合上面的算法和9楼的算法。

附加说明:
我们把阶乘的算法,通过两遍取对数,变成加法,是上面算法的关键,比如:
10! = 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 x 10
两边取对数(下面的log均以10为底,由于C语言中没有以10为底的对数函数,所以上面的代码中用了换底公式):
log(10!) = log1 + log2 + log3 + log4 + log5 + log6 + log7 + log8 + log9 + log10
这样一来就不会产生溢出,同时提高了运算效率。
将得到的结果的整数部分去掉,只保留小数部分,比如log(125) = 2.09691。其整数部分为2,去掉2,就相当于将原来的数字125,除以100(因为log100 = 2),也就是说log(1.25) = 0.09691。对数的反函数是指数函数,所以第一位数可以通过[10^0.09691]计算出来,即1。其中[]表示向下取整。

推而广之,如果要得出前面的两位数,就将log(125) - 1 = 1.09691, 然后[10^1.09691] = 12

对于楼主这个题目,也是如此。比如要计算出10000!的前三位数,按照上面的做法,也是很容易就可以搞定的。

不过你学长5行代码就搞定了,那是很nx了,方便话把他的答案贴出来,给大家学习学习。
uniqueroy 2011-07-16
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 pathuang68 的回复:]

C/C++ code

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial = 0.0;
do
{
……
[/Quote]

到13还是不行了。。。
13!第一位好像是9
pathuang68 2011-07-16
  • 打赏
  • 举报
回复

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial = 0.0;
do
{
cin >> n;

log_n_factorial = 0.5 * log(2 * 3.14159265358979 * (double)n) / log(10.0) + (double)n * log((double)n / 2.71828459045) / log(10.0);
log_n_factorial -= (int)log_n_factorial;

firstnumber = exp(log_n_factorial * log(10.0));

// 1. 用sterling公式计算较小数字的阶乘的时候,存在比较大的误差,随着数字的增大误差越小。
// 2. 用switch...case...处理几个比较小的数字,其他的(见default)就均可以使用sterling公式计算出来的结果了。
switch(n)
{
case 0:
cout << "1" << endl;
break;
case 1:
cout << "1" << endl;
break;
case 2:
cout << "2" << endl;
break;
case 3:
cout << "6" << endl;
break;
case 7:
cout << "5" << endl;
break;
case 8:
cout << "4" << endl;
break;
default:
cout << firstnumber << endl;
}
}while(n != 0); // n = 0时退出循环

return 0;
}
pathuang68 2011-07-16
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 pathuang68 的回复:]

这题应该是要用到sterling公式的,否则要么溢出,要么超时。但在用sterling公式时要注意:
1. 用sterling公式计算较小数字的阶乘的时候,存在比较大的误差,随着数字的增大误差越小。
2. 用switch...case...处理几个比较小的数字,其他的(见default)就均可以使用sterling公式计算出来的结果了。

在9楼代码的基础上做了一些修改,楼主可以在这个基……
[/Quote]
晕,每个case后,忘记加break;了。
pathuang68 2011-07-16
  • 打赏
  • 举报
回复
这题应该是要用到sterling公式的,否则要么溢出,要么超时。但在用sterling公式时要注意:
1. 用sterling公式计算较小数字的阶乘的时候,存在比较大的误差,随着数字的增大误差越小。
2. 用switch...case...处理几个比较小的数字,其他的(见default)就均可以使用sterling公式计算出来的结果了。

在9楼代码的基础上做了一些修改,楼主可以在这个基础上再修改一下。供参考:

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial = 0.0;
do
{
cin >> n;

log_n_factorial = 0.5 * log(2 * 3.14159265358979 * (double)n) / log(10.0) + (double)n * log((double)n / 2.71828459045) / log(10.0);
log_n_factorial -= (int)log_n_factorial;

firstnumber = exp(log_n_factorial * log(10.0));

// 1. 用sterling公式计算较小数字的阶乘的时候,存在比较大的误差,随着数字的增大误差越小。
// 2. 用switch...case...处理几个比较小的数字,其他的(见default)就均可以使用sterling公式计算出来的结果了。
switch(n)
{
case 0:
cout << "1" << endl;
case 1:
cout << "1" << endl;
case 2:
cout << "2" << endl;
case 3:
cout << "6" << endl;
case 7:
cout << "5" << endl;
case 8:
cout << "4" << endl;
default:
cout << firstnumber << endl;
}
}while(n != 0);

return 0;
}

赵4老师 2011-07-15
  • 打赏
  • 举报
回复
用python语言,想求第几位,就求第几位。
uniqueroy 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 sanguine1211 的回复:]

引用 15 楼 uniqueroy 的回复:

C/C++ code
long long n, sum1;
n = 13;
sum1 = nmultiple(n);
printf("%ld\n", sum1);
long double sum;
sum = (long double)sum1;//这里直接给错了。。。1932053504直接给成了6227020800.000000……
[/Quote]

刚跑了你的, 到13也不行了啊, 咱应该都是double小数位太长的问题吧..
uniqueroy 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 sanguine1211 的回复:]

引用 15 楼 uniqueroy 的回复:

C/C++ code
long long n, sum1;
n = 13;
sum1 = nmultiple(n);
printf("%ld\n", sum1);
long double sum;
sum = (long double)sum1;//这里直接给错了。。。1932053504直接给成了6227020800.000000……
[/Quote]

一辈子看不懂斯特林公式...
sanguine1211 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 uniqueroy 的回复:]

C/C++ code
long long n, sum1;
n = 13;
sum1 = nmultiple(n);
printf("%ld\n", sum1);
long double sum;
sum = (long double)sum1;//这里直接给错了。。。1932053504直接给成了6227020800.000000, 谁知道为什……
[/Quote]




#include<iostream>
#include<cmath>
#include<cstdlib>
#define pi 3.141592653
#define exp 2.718281828
using namespace std;
int main()
{
int n,m;
double s;
while(cin>>n)
{
s=log10(sqrt(2*n*pi))+n*log10(n/exp);
m=(int)pow(10.0,s-(int)s);
if(n==0)
cout<<"1"<<endl;
else if(n==1)
cout<<"1"<<endl;
else if(n==2)
cout<<"2"<<endl;
else if(n==3)
cout<<"6"<<endl;
else if(n==7)
cout<<"5"<<endl;
else if(n==8)
cout<<"4"<<endl;
else
cout<<m<<endl;
}
return 0;
}
sanguine1211 2011-07-15
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 uniqueroy 的回复:]

C/C++ code
long long n, sum1;
n = 13;
sum1 = nmultiple(n);
printf("%ld\n", sum1);
long double sum;
sum = (long double)sum1;//这里直接给错了。。。1932053504直接给成了6227020800.000000, 谁知道为什……
[/Quote]

我是这样做的……AC了……
有什么办法能去掉下面这些枚举吗?
#include<iostream>
#include<cmath>
#include<cstdlib>
#define pi 3.141592653
#define exp 2.718281828
using namespace std;
int main()
{
int n,m;
double s;
while(cin>>n)
{
s=log10(sqrt(2*n*pi))+n*log10(n/exp);
m=(int)pow(10.0,s-(int)s);
if(n==0)
cout<<"1"<<endl;
else if(n==1)
cout<<"1"<<endl;
else if(n==2)
cout<<"2"<<endl;
else if(n==3)
cout<<"6"<<endl;
else if(n==7)
cout<<"5"<<endl;
else if(n==8)
cout<<"4"<<endl;
else
cout<<m<<endl;
}
return 0;
}
uniqueroy 2011-07-14
  • 打赏
  • 举报
回复
	long long n, sum1;
n = 13;
sum1 = nmultiple(n);
printf("%ld\n", sum1);
long double sum;
sum = (long double)sum1;//这里直接给错了。。。1932053504直接给成了6227020800.000000, 谁知道为什么吗
printf("%Lf\n", sum);
while(1)
{
if(sum > 10)
sum /= 10;
else
break;
}
printf("%Lf\n", sum);
int i;
for(i = 1; i < 10; i ++)
if((sum - i) < 1)
break;
printf("%d", i);
uniqueroy 2011-07-14
  • 打赏
  • 举报
回复
噢, 我刚从1试到13, 1-12都正确, 13好像就不行了,是不是太长了 强转double读不到了
uniqueroy 2011-07-14
  • 打赏
  • 举报
回复
long long nmultiple(long long n)
{
if(n > 1)
n = n * nmultiple(n - 1);
return n;
}


void main()
{
long long n, sum1;
n = 13;
sum1 = nmultiple(n);
printf("%ld\n", sum1);
double sum;
sum = (double)sum1;
while(1)
{
if(sum > 10)
sum /= 10;
else
break;
}
printf("%f\n", sum);
int i;
for(i = 1; i < 10; i ++)
if((sum - i) < 1)
break;
printf("%d", i);
}


这样应该是可以的
flora186 2011-07-14
  • 打赏
  • 举报
回复
看着就晕菜...
pathuang68 2011-07-14
  • 打赏
  • 举报
回复
还是用9楼的吧,10楼的还不如9楼滴:(
pathuang68 2011-07-14
  • 打赏
  • 举报
回复
吃完饭了。修改了一下,下面这样应该就全部可以了。

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial = 0.0;
cin >> n;


log_n_factorial = 0.5 * log(2 * 3.14159265358979 * (double)n) / log(10.0) + (double)n * log((double)n / 2.71828459045) / log(10.0);
log_n_factorial -= (int)log_n_factorial;

firstnumber = (int)(exp(log_n_factorial * log(10.0))+ 0.5); // 改成向上取整

cout << firstnumber << endl;

return 0;
}
pathuang68 2011-07-14
  • 打赏
  • 举报
回复
这就是你要的答案,供参考。数字越大结果应该越准确。

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

int main(int argc, char *argv[])
{
int n = 0;
int firstnumber = 0;
double log_n_factorial = 0.0;
cin >> n;


log_n_factorial = 0.5 * log(2 * 3.14159265358979 * (double)n) / log(10.0) + (double)n * log((double)n / 2.71828459045) / log(10.0);
log_n_factorial -= (int)log_n_factorial;

firstnumber = exp(log_n_factorial * log(10.0));

cout << firstnumber << endl;

return 0;
}


稍微验证了一下,出7!的阶乘的第一位不准确外,其它的似乎都可以。
加载更多回复(8)

70,012

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧