题意是求 n 的阶乘的位数。
直接求 n 的阶乘再求其位数是不行的,开始时思路很扯淡,想直接用一个数组存每个数阶乘的位数,用变量 tmp 去存 n 与 n - 1 的阶乘的最高位的数的乘积,那么 n 的阶乘的位数就等于 n - 1 的阶乘的位数加 tmp 的位数再减去 1。
但这种做法是不对的,例如有可能最高位与 n 的乘积结果是 99,而其实 n 与其他位的乘积结果是能进到这一位的,也就是说实际应该在 n - 1 的阶乘位数上增加 2 ( 3 -1 ) 位。而在对样例测试时也发现 n 为 10 的时候结果尚正确,但当 n 为 20 的时候就比正确结果少了 1,也就是说发生了上述情况。
抱着侥幸心理,又再次将每次乘以最高位的做法调整成了每次乘以最高的两位,这一次当 n 为 20 时结果依然正确,但是内存超了......
错误代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int tmp,dig[10000009]; 4 int getdigit(int n) 5 { 6 int a(0); 7 while(n) 8 { 9 n/=10; 10 a++; 11 } 12 return a; 13 } 14 void make() 15 { 16 int digit; 17 dig[1] = 1; 18 dig[2] = 1; 19 dig[3] = 1; 20 dig[4] = 2; 21 tmp = 24; 22 for(int i = 5; i <= 10000000; i++) 23 { 24 tmp *= i; 25 digit = getdigit(tmp); 26 dig[i] = digit + dig[i-1] - 2; 27 for(int j = 2; j < digit; j++) tmp/=10; 28 } 29 } 30 int main() 31 { 32 int t,ans,n; 33 scanf("%d",&t); 34 make(); 35 while(t--) 36 { 37 scanf("%d",&n); 38 printf("%d ",dig[n]); 39 } 40 return 0; 41 }
在借鉴了其他人的做法后,才觉得对这道题有了一点正确的思路:
首先,一个数 x 的位数可以用以 10 为底取对数再向上取整的方法求得,即 digit( x ) = ceil ( log10( x ) );
那么,阶乘的位数可以直接求:digit( n! ) = ∑ log10( i ) ( i 从 1 取到 n )
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int main() 4 { 5 int t,n; 6 double ans; 7 scanf("%d",&t); 8 while(t--) 9 { 10 ans = 0; 11 scanf("%d",&n); 12 for(int i = 1; i <= n; i++) 13 { 14 ans += log10(i); 15 } 16 printf("%d ",(int)ans+1); 17 } 18 return 0; 19 }
另外,在求 n 的阶乘的时候用 Stirling 公式 也是很好的做法,
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const double pi = acos(-1); 4 int main() 5 { 6 int t,n,ans; 7 scanf("%d",&t); 8 while(t--) 9 { 10 scanf("%d",&n); 11 ans = ceil((log(n)*n - n + 0.5*log(2*pi*n) )/ log(10)); 12 printf("%d ",ans); 13 } 14 return 0; 15 }