原题链接:http://codeforces.com/contest/837/problem/D
题意:在n个数字中,取k个数,使这些数的乘积后缀“0”的个数最大,输出后缀0的最大数量。
思路:显然只有含有因子2和5的数相乘才能得到10的倍数,所以对每个数求因子2和5的个数。
这里运用背包的思想,对于 i 个数,假设总共有 j 个2因子数目,能够得到的5的因子数目最大为dp[i][[j],状态转移方程为:
dp[i][j]=max(dp[i][j], dp[i-1][dp[j-num_two]+num_five])
其中num_two和num_five是枚举到的某个数所含2和5的因子数。
最后求出min(i, dp[i][j])的最大值即可。
AC代码:
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 using namespace std; 6 const int MAXN=205; 7 const int INF=10000000; 8 int dp[MAXN][MAXN*61]; 9 int main() 10 { 11 int n,k; 12 long long a; 13 scanf("%d %d", &n, &k); 14 int sum2=0; 15 for(int i=0;i<MAXN;i++){ 16 for(int j=0;j<MAXN*61;j++) 17 dp[i][j]=-INF; 18 } 19 dp[0][0]=0; 20 for(int s=1;s<=n;s++){ 21 scanf("%I64d", &a); 22 int x=0,y=0; 23 while(a%2==0){ 24 a/=2; 25 x++; 26 } 27 while(a%5==0){ 28 a/=5; 29 y++; 30 } 31 sum2+=x; 32 for(int i=min(s, k);i>=1;i--){//避免重复计算导致答案错误,从大到小 33 for(int j=x;j<=sum2;j++){ 34 dp[i][j]=max(dp[i-1][j-x]+y, dp[i][j]); 35 } 36 } 37 } 38 int res=0,tmp; 39 for(int j=0;j<=sum2;j++){ 40 tmp=min(j, dp[k][j]); 41 res=max(tmp, res); 42 } 43 printf("%d ", res); 44 return 0; 45 }