1. 程式人生 > >大數問題--超大數(10000以內)的階乘

大數問題--超大數(10000以內)的階乘

問題分析:很容易發現,由於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,那麼製表肯定會比第二種程式碼節省很多時間的。