笔者总结自己的思路,有以下两种方法解决求幂的长度,求阶乘的长度。从而解决形如
“请你计算数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所能表示的范围,无法存储哨兵,这类情况第二种方法也无能为力。