【Codeforces837D】Round Subset
本题在洛谷上的链接:https://www.luogu.org/problem/show?pid=CF837D
好坑!绝对有毒!
我的CF账号还没有权限提交,各种未知错误,把代码改得和题解几乎一样才过,%lld和typedef都不支持吗???动规思想及细节处理当然也很坑。
这道题思想很简单,为了求末尾0的个数,就是要求分别分解出2和5的个数最小值,可以设dp[i][j][a][b]表示从前i个数中选取j个数,乘积分解出a个2,b个5是否可行,用min(a,b)更新答案即可。
但还可以再优化,设dp[i][j][l]表示从前i个数中选取j个数,乘积分解出l个5时,最多还可以分解出几个2,就可以用min(l,dp[i][j][l])去更新答案。
对的,这其实就是个背包问题,讨论每个数取或不取。
另外时间上每什么问题,但空间却会爆,所以还要用到滚动数组。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 2, maxk = 205, max5 = 6000; 9 10 int dp[maxn][maxk][max5], sum2[maxk], sum5[maxk], ans; 11 12 int main() { 13 int n, k; 14 scanf("%d%d", &n, &k); 15 long long a; 16 for (int i = 1; i <= n; ++i) { 17 cin >> a; 18 while (a % 2 == 0) ++sum2[i], a /= 2; 19 while (a % 5 == 0) ++sum5[i], a /= 5; 20 } 21 memset(dp, -1, sizeof(dp)); 22 dp[0][0][0] = 0; 23 for (int i = 1; i <= n; ++i) 24 for (int j = 0; j <= i && j <= k; ++j) 25 for (int l = 0; l < max5; ++l) { 26 dp[i % 2][j][l] = dp[(i - 1) % 2][j][l]; 27 if (j >= 1 && l >= sum5[i] && dp[(i - 1) % 2][j - 1][l - sum5[i]] != -1) 28 dp[i % 2][j][l] = max(dp[i % 2][j][l], dp[(i - 1) % 2][j - 1][l - sum5[i]] + sum2[i]); 29 } 30 for (int l = 0; l < max5; ++l) 31 ans = max(ans, min(l, dp[n % 2][k][l])); 32 printf("%d", ans); 33 return 0; 34 }