给你一个序列a,求a中有多少个子段使得子段的乘积的末尾有k个0,写出c++代码
时间: 2024-02-11 19:07:57 浏览: 33
这也是一个数位 DP 题目,可以使用前缀积和数位 DP 算法求解。
具体来说,我们可以使用前缀积来求出任意一个区间 [l,r] 的乘积 x,然后统计末尾有多少个 0。接着,我们可以使用数位 DP 来处理末尾有多少个 0,具体来说,我们可以使用一个二维数组 dp[i][j] 表示考虑到第 i 位,末尾有 j 个 0 的子段数量。转移时,我们可以枚举当前位置的数字,然后统计当前数字对子段末尾 0 的贡献,即当前数字质因子中 2 和 5 的个数,然后将贡献加入 dp 数组中。
最终的答案即为所有以任意位置结尾的子段中符合条件的数量之和。时间复杂度为 O(nlogB),其中 B 为序列中元素的最大值。
参考代码如下:
```c++
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXK = 10;
int n, k;
int a[MAXN];
int cnt[MAXK];
int dp[MAXN][MAXK];
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
long long ans = 0;
for (int l = 1; l <= n; l++) {
// 重置状态
for (int i = 0; i < k; i++) {
cnt[i] = 0;
}
for (int r = l; r <= n; r++) {
// 计算区间乘积的末尾 0 的个数
int x = a[r];
int zero = 0;
while (x % 10 == 0) {
zero++;
x /= 10;
}
cnt[zero]++;
// 计算末尾有 k 个 0 的子段数量
dp[r][0] = 1;
for (int j = 1; j < k; j++) {
dp[r][j] = 0;
}
for (int j = 0; j < k; j++) {
int t = (j + zero) % k;
dp[r][t] += cnt[j];
}
ans += dp[r][k - 1];
}
}
cout << ans << endl;
return 0;
}
```
阅读全文