问题分析:很容易发现,由于N的范围很大,一般简单的阶乘算法肯定会溢出,因为当20!已经接近long long的上限了。
所以得用大数问题的解法,就是模拟运算:
下面基于上面的思想,给出此题的两种代码实现:
①事先制表:
#include<bits/stdc++.h>
using namespace std;
#define N 10005
vector<int> factorial[N];
void calc(int n) //计算
{
int len = factorial[n-1].size();
for(int i = 0;i < len;++i)
{
factorial[n].push_back(factorial[n-1][i]*n);
}
int jinwei = 0; //变量jinwei用于保存下位进上去的数字,初始为0
for(int i = len-1;i >= 0;--i)
{
int temp = jinwei + factorial[n][i]; //变量temp用于保存该位上加上进位的数字后的结果
jinwei = temp/10; //此时jinwei更新为temp值十位上的数字
factorial[n][i] = temp%10; //此时该位上的数字应为temp值个位上的数字
}
while(jinwei){ //将factorial[n]最前面的那位上进的数字插入到向量前面,由于jinwei可能大于9(即是一个二位数),故要用一个while循环,而不能简单地把jinzhi插到前面
factorial[n].insert(factorial[n].begin(),jinwei%10);
jinwei /= 10;
}
}
void make_table() //制表
{
factorial[1].push_back(1); //设定初始值
for(int i = 2;i < 1000;++i){
calc(i);
}
}
int main()
{
make_table();
int n;
while(cin >> n){
int len = factorial[n].size(); //输出存储n!的向量factorial[n]
for(int i = 0;i < len;++i)
cout << factorial[n][i];
cout << endl;
}
return 0;
}
②直接计算,没有制表
#include<bits/stdc++.h>
using namespace std;
vector<int> v;
int n;
int main()
{
int n;
while(cin >> n){
if(n == 1) cout << '1' << endl; //n为1时,直接打印结果
else
{
v.push_back(1); //先向向量中插入一个数字
for(int i = 2;i <= n;++i){ //逐步操作到n
int len = v.size();
for(int j = 0;j < len;++j){ //将向量里每一个元素都乘上i
v[j] *= i;
}
int jinwei = 0; //变量jinwei用于保存该位要向上进位的数字
for(int j = len-1;j >= 0;--j){
int temp = jinwei + v[j]; //变量temp用于保存该位上加上进上来的数字后的结果
jinwei = temp/10; //更新变量jinwei
v[j] = temp%10; //确定该位上的数字
}
while(jinwei){ //对最前面一位进上去的数字进行处理,由于这个数字可能不止一位,所以不能简简单单地插到最前面,而是要用一个while循环一步步插到最前面
v.insert(v.begin(),jinwei%10);
jinwei /= 10;
}
}
int len = v.size(); //打印结果
for(int i = 0;i < len;++i){
cout << v[i];
}
cout << endl;
}
v.clear();
}
return 0;
}
PS:一开始,为了节省时间,我采用了第一种代码,制了表,可是提交上去发现,超出内存限制,仔细一想也对,毕竟当n为3000时,结果就已经在屏幕上显示过百行了,放在内存里,肯定会花费很多内存的。
然后就才采用了第二种代码,结果过了,其实因为题目测试样例的n不会测很多的,所以完全没必要采用制表方法来节省时间,若是要测很多n,那么制表肯定会比第二种代码节省很多时间的。