【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 }
AC代码

 

posted @ 2018-11-01 18:03  Mr^Kevin  阅读(126)  评论(0编辑  收藏  举报