階乘之和
例題:輸入n,計算s = 1!+2!+3!+...+n!的未6位(不含前導0)。n<=10^6,n!表示前n個正整數之積。
樣例輸入:
樣例輸出:
分析:這個任務看似不難,實際卻有陷阱。先看如下**:
**1(有缺陷):
//abc
#include#includeint main()
printf("%ld\n",s % 1000000);
return 0;
}
#include#includeint main()首先是演算法改進:對每部階乘進行求餘,隨後的結果s再進行求餘。先看測試結果:printf("%d\n",s);
printf("time used = %.2f\n",(double)clock() / clocks_per_sec);
return 0;
}
輸入20,輸出結果:820313; 輸入40,輸出結果:940313; 輸入100,輸出:940313;
輸入160,輸出結果:940313; 輸入1600,輸出結果:940313..........
可以發現從40開始,答案始終不變。這是因為當25!末尾有6個0,所以從第5項開始,後面的所有項都不會影響和的末6位數字。
什麼意思呢:1!-10!舉例如下:
1~10的階乘如下:所以有此可見。。。。所以只需要在程式的最前面加一條語句「if(n>25) n=25;」,效率和溢位將都不存在問題。1!=1
2!=2
3!=6
4!=24
5!=120
6!=720
7!=5040
8!=40320
9!=362880
10!=3628800
下面來看程式中其他的東西:這個程式的真正特別之處在於計時函式clock()的使用。該函式返回程式目前為止執行的時間。
這樣,在程式結束之前呼叫此函式,便可獲得整個程式的執行時間。這個時間除以常熟clocks_per_sec之後得到的值以「秒」為單位。
(c語言函式
clock
() 功 能:
返回處理器呼叫某個程序或函式所花費的時間。
用 法:
clock_t
clock
(
void
);
說明:
clock_t
其實就是
long
,即長整形。該函式返回值是硬體滴答數,要換算成秒或者毫秒,需要除以clk_tck或者 clk_tck
clocks_per_sec。比如,在vc++6.0下,這兩個量的值都是1000,這表示硬體滴答1000下是1秒,因此要計算乙個程序的時間,用
clock
()除以1000即可。
)
輸入「20」,按enter鍵後,系統瞬間給出了答案820313。但是,輸出的time used居然不是0!其原因在於,鍵盤輸入的時間也被使計算在內——這的確
是程式啟動之後才進行的。為了避免輸入資料的時間影響測試結果,可以使用一種稱為「管道」的小技巧;在windows命令列下執行echo 20|abc,作業系統
會自動把20輸入,其中abc是程式名。
測試可知,程式的執行時間和n的平方成正比。(即程式的時間複雜度為o(n^2))).
我們來測試一下這個程式(測試環境為dev-c++):
當輸入10時,輸出37913,結果正確。 但當輸入100時,輸出-961703。
我們知道int最大值為2^31-1,沒錯,在乘法累加的過程中,整形s的資料溢位。因為我們只求的是階乘之和
的最後六位,沒必要求出階乘s的結果,所以可以從如下進行改進(過求出s的結果,難度更大)。
想要解決這個問題,需要運用這個數學知識:
只要計算包含加法,減法和乘法的整數表示式除以正整數n的餘數,可以在每部計算之後對n取餘,結果不變。
下面請看改進過後的**2,還會有新的東西:
#include#includeint main()
printf("%d\n",s);
printf("time used = %.2f\n",(double)clock() / clocks_per_sec);
return 0;
}
首先是演算法改進:對每部階乘進行求餘,隨後的結果s再進行求餘。
先看測試結果:
輸入20,輸出結果:820313; 輸入40,輸出結果:940313; 輸入100,輸出:940313;
輸入160,輸出結果:940313; 輸入1600,輸出結果:940313..........
可以發現從40開始,答案始終不變。這是因為當25!末尾有6個0,所以從第5項開始,後面的所有項都不會影響和的末6位數字。
什麼意思呢:1!-10!舉例如下:
1~10的階乘如下:
1!=1
2!=2
3!=6
4!=24
5!=120
6!=720
7!=5040
8!=40320
9!=362880
10!=3628800
所以有此可見。。。。所以只需要在程式的最前面加一條語句「if(n>25) n=25;」,效率和溢位將都不存在問題。
下面來看程式中其他的東西:這個程式的真正特別之處在於計時函式clock()的使用。該函式返回程式目前為止執行的時間。
這樣,在程式結束之前呼叫此函式,便可獲得整個程式的執行時間。這個時間除以常熟clocks_per_sec之後得到的值以「秒」為單位。
(c語言函式clock() 功 能:
返回處理器呼叫某個程序或函式所花費的時間。
用 法: clock_t clock(void);
說明:clock_t其實就是long,即長整形。該函式返回值是硬體滴答數,要換算成秒或者毫秒,需要除以clk_tck或者 clk_tck
clocks_per_sec。比如,在vc++6.0下,這兩個量的值都是1000,這表示硬體滴答1000下是1秒,因此要計算乙個程序的時間,用clock()除以1000即可。)
輸入「20」,按enter鍵後,系統瞬間給出了答案820313。但是,輸出的time used居然不是0!其原因在於,鍵盤輸入的時間也被使計算在內——這的確
是程式啟動之後才進行的。為了避免輸入資料的時間影響測試結果,可以使用一種稱為「管道」的小技巧;在windows命令列下執行echo 20|abc,作業系統
會自動把20輸入,其中abc是程式名。
測試可知,程式的執行時間和n的平方成正比。(即程式的時間複雜度為o(n^2))).
演算法實現求n的階乘(防止溢位)
求大整數n階乘,在找工作筆試和面試的過程中,不止一次遇到這個問題,用乙個for迴圈迭代出的結果肯定是不行的,即直接用int,預設是32位,它能表示的最大值為2,147,483,647,但是12的階乘為479,001,600,13的階乘為6,227,020,800,所以當n為13的時候已經溢位了。所以...
演算法實現求n的階乘(防止溢位)
求大整數n階乘,在找工作筆試和面試的過程中,不止一次遇到這個問題,用乙個for迴圈迭代出的結果肯定是不行的,即直接用int,預設是32位,它能表示的最大值為2,147,483,647,但是12的階乘為479,001,600,13的階乘為6,227,020,800,所以當n為13的時候已經溢位了。所以...
階乘之和 防止int型別溢位的小技巧 計時函式
計算前n個正整數階乘之和的後六位 注意點是,用乙個int型別儲存階乘之和時,要防止溢位 一,在每一次處理階乘 fa 或者階乘之和 s 時,都對10 6取餘,這樣最終結果不變,還避免了越界 二,計時函式可以用來觀察程式執行時間 用法 printf f double clock clocks per s...