HihoCoder1706 : 末尾有最多0的乘积(还不错的DP)

描述

给定N个正整数A1, A2, ... AN。  

小Hi希望你能从中选出M个整数,使得它们的乘积末尾有最多的0。

输入

第一行包含两个个整数N和M。  

第二行包含N个整数A1, A2, ... AN。  

对于30%的数据,1 ≤ M ≤ N ≤ 12  

对于100%的数据,1 ≤ M ≤ N ≤ 100  1 ≤ Ai ≤ 1000000000

输出

末尾最多的0的个数

样例输入

4 2  
8 25 30 40

样例输出

3

DP[N][M][X]表示前面N个数选择M个数有X个5时,最多有多少个2。

比赛的时候一直在想4维的做法,最后60分,GG了。想来还是背包类DP做少了。

#include<cmath>
#include<cstring>
#include<memory.h>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=110;
int t[maxn],f[maxn],ans;
int N,M;
int dp[102][102][902];
int main()
{
    int x,y,i,j,k,sum=0;
    scanf("%d%d",&N,&M);
    for(i=1;i<=N;i++){
        scanf("%d",&x);y=x;
        while(y%5==0) {
            t[i]++; y/=5;
            sum++;
        }
        while(x%2==0){
            f[i]++;x/=2;
        }
    }
    memset(dp,-1,sizeof(dp));
    dp[0][0][0]=0;
    sum=min(sum,900);
    for(i=1;i<=N;i++) 
     for(j=0;j<=min(i,M);j++)
      for(k=0;k<=sum;k++){
         dp[i][j][k]=dp[i-1][j][k];
         if(k>=t[i]&&j>=1&&dp[i-1][j-1][k-t[i]]!=-1) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][k-t[i]]+f[i]); 
    }
    for(i=1;i<=sum;i++) ans=max(ans,min(dp[N][M][i],i));
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/8544756.html