1. 程式人生 > >Codeforces 837D Round Subset(背包)

Codeforces 837D Round Subset(背包)

邊界 efi set test blog 個數 復雜度 names 預處理

題目鏈接 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;
}

Codeforces 837D Round Subset(背包)