Problem D
Time Limit : 10000/5000ms (Java/Other) Memory Limit : 262144/262144K (Java/Other)
Problem 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 3Sample Output
1 2 6
这题一开始看起来真的好简单 以至于我飞快写完了然后Time Limit Exceeded 好像是我第一次接触大数?后来去练了大数的加法然后又听老师讲了一遍这个才慢慢理解 真的想了挺久 感觉自己好笨..救命
下面更多的是老师的思路 感觉通过这道题学到了很多 以后还要再多敲一敲关于大数的题目
最后优化完的代码运行出来只有499ms 真的好快啊
题意:
求N! ,注意的是N的范围[0,10000],即要考虑程序能够处理“10000!”
思路:
首先要考虑数据N!的位数,以便于知道声明多大的数组来存储。估算最大值10000!的位数:
10000! = 10000*9999*9998*...*5*4*3*2*1
位数= 5 + 9000*4 + 900*3 + 90*2 + 10*1 => 38865
位数计算的解释:1000~9999共有9000个,每乘一个这样的数会让结果增加约4位,因此为9000*4,其它项式依此类推。
综上,可以开一个40000的int数组存放,然后用常规法去计算。
优化:
十万进制:int数组一个元素只存1位数字太浪费了,不如让它的空间发挥到极限,即数组的一个元素存一个不
超过10^5的数(为什么是这个值,而不是更大或更小的值,见代码中的注释)。改进版是一个元素存5位十进制数,
位数是前面的1/5,因此开数组大小开为:8000
代码:
#include<iostream>
#define N 8000
int a[N];//定义为全局数组以防栈溢出,但是对于本题来说应该还不需要
int main()
{
using namespace std;
int n,i,j,k,t,digit;
while(cin>>n)
{
if(n==0||n==1)
{
cout<<1<<endl;
continue;
}
a[0]=1;//真正的大数从位置1开始,起始值为1,然后依次乘以2,3,4,...n
digit=1;//有效位:初始为1
for(i=2;i<=n;i++)//分别让2,3,4...n去乘大数s[]
{
for(j=0,t=0;j<digit;j++)//计算i乘大数s[]:让i分别乘大数s[]中的每一个元素s[j]
{
k=a[j]*i+t;//t为进位 ★★★★★解释为什么本题的“十万进制”是极限。因为:i可以大到10^4,t也可以接近10^4,而k是int类型(不超过10位),由此得出进制的极限值。
t=k/100000;//★★
a[j]=k%100000;//★★
}
//原有效位数再往前推进,而且可能同时进几位
while(t)
{
a[digit]=t%100000;//★★
t/=100000;//★★
digit++;
}
}
cout<<a[digit-1];//第一个元素(最高位位置)不要输出多余的0//★★
digit-=2;
while(digit+1)
printf("%05d",a[digit--]);//第二、三及后面的元素要输出多余的0
cout<<endl;
}
}