1. 程式人生 > >【Codeforces837D】Round Subset

【Codeforces837D】Round Subset

open col https bsp space urn nbsp 滾動數組 str

本題在洛谷上的鏈接: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代碼

【Codeforces837D】Round Subset