筆者總結自己的思路,有以下兩種方法解決求冪的長度,求階乘的長度。從而解決形如
“請你計算數a的b次冪共有多少位(十進制的數)!”
“N! (N的階乘) 是非常大的數,計算公式爲:N! = N * (N - 1) * (N - 2) * … * 2 * 1)。現在需要知道N!有多少(十進制)位。”之類的問題。
方法一:調用log10()函數
解決階乘的位數
int digit(int n)//求數n的階乘的長度
{
double length = 0;
for(int i =1;i<=n;++i)
length += log10((double)i);
//此處爲進一法,length爲double型變量,沒有絕對的整數值,只有可能能是逼近某個整數
return (int)(length+1);
}
解決冪的位數
和解決階乘的位數相似,區別在於兩個變量
int digit(int a, int b)//求數a的b次冪的長度
{
double length = 0;
for(int i =1;i<=b;++i)
length += log10((double)a);
//此處爲進一法,length爲double型變量,沒有絕對的整數值,只有可能能是逼近某個整數
return (int)(length+1);
}
方法二:設哨兵對10取餘法
解決階乘的位數
題目來源
http://acm.nefu.edu.cn/problemShow.php?problem_id=65
Description
N! (N的階乘) 是非常大的數,計算公式爲:N! = N * (N - 1) * (N - 2) * … * 2 * 1)。現在需要知道N!有多少(十進制)位。
Input
每行輸入1個正整數N。0 < N < 1000000
Output
對於每個N,輸出N!的(十進制)位數。
Sample Input
1
3
32000
1000000
Sample Output
1
1
130271
5565709
思路
設置一個很大的數,在對階乘不斷更新的過程中一旦超過這個數就dui10取餘,同時更新長度,以防止階乘越界。
根據0 < N < 1000000 ,筆者定義int64_t M = 1e10
const int64_t M = 1e10;
AC代碼
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<inttypes.h>
using namespace std;
int64_t sum = 1;const int M = 1e10;//設置哨兵
int main(){
int n;//n<=1000000
while(cin>>n){
if(n<=3) cout<<1<<endl;//0,1,2,3的階乘的位數爲1位
else{
int length = 0;sum = 1;//length爲階乘的長度
for(int i=2;i<=n;i++){
while(sum > M){
sum /= 10;
length++;
}
sum *= i;
}
while(sum){
sum /= 10;
length++;
}
cout<<length<<endl;
}
}
return 0;
}
解決冪的長度
和上述代碼下相比只是只改變了一點點、
題目來源
http://acm.nefu.edu.cn/problemShow.php?problem_id=94
Description
請你計算數a的b次冪共有多少位(十進制的數)!
Input
輸入數據有多組,每組二個正整數分別爲a和b,其中(1<=a<=10000,1<=b<=10000)
Output
輸出a^b(a的b次冪)的值共有多少位?
Sample Input
2 3
1 1
10 5
Sample Output
1
1
6
AC代碼
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<inttypes.h>
using namespace std;
int64_t sum = 1;const int M = 1e10;
//計算數a的b次冪共有多少位 其中(1<=a<=10000,1<=b<=10000)
int64_t getpowLen(int a,int b)
{
if(b == 0) return 1;
int64_t ans = 0;int64_t sum = 1;//ans存放長度,sum用於更新冪
for(int i=1;i<=b;i++){
while(sum > M){
sum /= 10;
ans++;
}
sum *= a;
}
while(sum){ //求最後餘下的長度
sum /= 10;
ans++;
}
return ans;
}
int main(){
int a,b;
while(cin>>a>>b)
cout<<getpowLen(a,b)<<endl;
return 0;
}
總結
筆者認爲運用log10()函數更加準確,同時也對算術基本定理有了新的運用。
對於第二種算法,如果題目給出的n的長度最大爲1018,那麼哨兵會爆出int64_t所能表示的範圍,無法存儲哨兵,這類情況第二種方法也無能爲力。