大數問題--超大數(10000以內)的階乘
阿新 • • 發佈:2019-02-08
問題分析:很容易發現,由於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,那麼製表肯定會比第二種程式碼節省很多時間的。