P1591 阶乘数码
-
考点:高精度 * 低精度
-
测评链接:P1015;
-
讲评视频:
稍后上传;
分析&题意
这道题要求的是在给定的阶乘 n ! n! n! 中,某个特定数码(比如 0 , 1 , 2 , . . . , 9 0, 1, 2, ..., 9 0,1,2,...,9 )出现的次数。阶乘 n ! n! n! 是从 1 1 1 乘到 n n n 的所有整数的乘积,即 n ! = 1 ∗ 2 ∗ . . . ∗ n − 1 ∗ n n!=1 * 2 \ * ... \ * n-1 * n n!=1∗2 ∗... ∗n−1∗n。
例子解释
以样例输入为例:
- 第一组数据:
n
=
5
n=5
n=5,数码
a
=
2
a=2
a=2
- 5 ! = 1 × 2 × 3 × 4 × 5 = 120 5!=1×2×3×4×5=120 5!=1×2×3×4×5=120
- 在 120 120 120 中,数码 2 2 2 出现了 1 1 1 次。
- 因此,输出是
1
。
- 第二组数据:
n
=
7
n=7
n=7,数码
a
=
0
a=0
a=0
- 7 ! = 1 × 2 × 3 × 4 × 5 × 6 × 7 = 5040 7!=1×2×3×4×5×6×7=5040 7!=1×2×3×4×5×6×7=5040
- 在 5040 5040 5040 中,数码 0 0 0 出现了 2 2 2 次。
- 因此,输出是
2
。
- 本题本质上就是高精度( 阶乘 ) * 低精度 ( 1 ∼ n 1 \sim n 1∼n),注意细节即可, a n s [ 1 ] = 1 ans[1] = 1 ans[1]=1 表示为 1 1 1 的阶乘初始化为 1 1 1。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 5000;
int T, n, target;
int ans[N];
// 高乘以低
int fact( int n, int a[] ) {
int lenc = 1; // 进位
for (int i = 1, j, x; i <= n; i++) { // j 有效位数, x 进位
// 高精度 * 低精度,进位初始化为 0
x = 0;
for (j = 1; j <= lenc; j++) { // 乘积
a[j] = (a[j] * i) + x; // 被乘数[j] * 乘数 i + 进位
x = a[j] / 10; // 处理进位
a[j] %= 10; // 保留个位
}
while ( x > 0 ) //最高位进位
{
a[j++] = x % 10;
x /= 10;
}
lenc = j-1; // j 后退一位指向最高位有效位
}
return lenc; //实际有效位
}
ll count( int a[], int len, int t ) {
ll cnt = 0;
for (int i = len; i >= 1 ; i--) // 统计有效数码
if ( a[i] == t )
cnt++;
return cnt;
}
int main() {
cin >> T;
while ( T-- ) {
cin >> n >> target;
memset( ans, 0, sizeof ans );
ans[1] = 1; // 1 的阶乘为 1,否则
// 求阶乘,存放到 ans 数组中,返回长度
int len = fact( n, ans );
// 统计数码 target 出现的次数
cout << count( ans, len, target) << endl;
}
}