题目链接:[http://codeforces.com/problemset/problem/837/D]
分析:
末尾为零,显然是由2*5得到的。
对每一个
ai
a
i
进行分解,得到2和5的数量。大概计算一下,2的数量最多有12800个,5的数量最多有6000个,所以用5的数量作为背包容量,计算最多可以有多少个2。
转移方程为
dp[i][k][j]=max{dp[i−1][k−1][j−x[i]]+y[i]}
d
p
[
i
]
[
k
]
[
j
]
=
m
a
x
{
d
p
[
i
−
1
]
[
k
−
1
]
[
j
−
x
[
i
]
]
+
y
[
i
]
}
其中, 1≤i≤n,1≤k≤m 1 ≤ i ≤ n , 1 ≤ k ≤ m , xi,yi x i , y i 分别为第 i i <script type="math/tex" id="MathJax-Element-80">i</script>个数5的数量和2的数量
对转移方程降维度。
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define ll long long
const ll INF = 0x7ffffff;
int n,m,sum,x[220],y[220];
ll a,ans,f[220][6000];
int main()
{
scanf("%d %d",&n,&m);
for (int i=0;i<n;i++)
{
scanf("%I64d",&a);
ll now = a;
while (now % 5 == 0)
{
x[i]++;
now /= 5;
}
sum += x[i];
now = a;
while (now % 2 == 0)
{
y[i]++;
now >>= 1;
}
}
for (int k=0;k<=m;k++)
for (int j=0;j<6000;j++) f[k][j] = -INF;
f[0][0] = 0;
for (int i=0;i<n;i++)
{
for (int k=m;k>0;k--)
for (int j=x[i];j<=sum;j++)
f[k][j] = max(f[k][j],f[k-1][j-x[i]]+y[i]);
}
for (int j=0;j<=sum;j++)
{
ll now = f[m][j];
if (j < now) now = j;
ans = max(now,ans);
}
printf("%I64d\n",ans);
return 0;
}