Codeforces 837D Round Subset(背包)
题目链接 Round Subset
题意 在n个数中选择k个数,求这k个数乘积末尾0个数的最大值。
首先我们预处理出每个数5的因子个数c[i]和2的因子个数d[i]
然后就可以背包了。
设f[i][j]为选i个数,5的因子总和为j时,2的因子总和的最大值。
则状态转移方程为 $f[i][j] = max(f[i - 1][j - c[k]] + d[k])$
注意边界条件
时间复杂度$O(5200nk)$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 210; int n, k, m; LL a[N]; int b[N]; int f[N][6010]; int ans = 0; int c[N], d[N]; int main(){ scanf("%d%d", &n, &m); rep(i, 1, n) scanf("%lld", a + i); rep(i, 1, n){ for (; a[i] % 2 == 0; a[i] /= 2) ++d[i]; for (; a[i] % 5 == 0; a[i] /= 5) ++c[i]; } rep(j, 0, m) rep(k, 0, 5200) f[j][k] = -(1 << 30); f[0][0] = 0; rep(i, 1, n){ dec(j, m, 1){ rep(k, c[i], 5200) f[j][k] = max(f[j][k], f[j - 1][k - c[i]] + d[i]); } } rep(j, 0, 5200) ans = max(ans, min(f[m][j], j)); printf("%d\n", ans); return 0; }