对于要装满的01背包

对于要装满的 01 背包
新疆省赛(虚无的后缀)
链接:https://ac.nowcoder.com/acm/contest/15589/H
来源:牛客网

题目描述
给出 n 个数字,第 i 个数字为 a[i],我们从中选出 k 个数字,使得乘积后缀 0 的个数最多。
输入描述:
第一行,两个正整数 n,k(1 \leq k \leq n \leq 200)n,k(1≤k≤n≤200),第 2 行 n 个正整数表示 a_i(a_i \leq 10^{18})a
i

(a
i

≤10
18
)
输出描述:
输出一个整数,表示最多有多少个后缀 0
示例1
输入

2 2
20 5
输出

2
示例2
输入

3 2
2 5 20
输出

2

题解:
有多少个0,即看一个数分解后的质因子中2和5的最小值即可,故

本题可以看做是一个要装满的 01 背包 即可以先将之理解为 dp[i][j][k] 即对于前i个物品,剩余了5的个数时(可以看做01背包的重量)2的最大个数,因为眼严格算出5和2的个数,所以要求5的个数要全部被用完,即要求装满的完全背包,又因为如果直接dp三维数组可能会爆掉,所以可以将其压成一维的形式(注意要从大到小进行,因为大的值会被小的不断更新)于是就可以有如下代码

#include<cstdio>
#include<iostream>

using namespace std;
typedef long long ll;
int sum2[205];
int sum5[205];
int all;
int dp[205][205*30];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        ll x;
        cin>>x;
        while(x%2==0)  //统计2的个数
        {
            sum2[i]++;
            x/=2;
        }
        while(x%5==0)  //统计5的个数
        {
            sum5[i]++;
            x/=5;
        }
        all+=sum5[i];  //以5的个数作为背包容量
    }
    for(int i=0;i<=n;i++)
        for(int j=0;j<=all;j++)
            dp[i][j]=-2e9;   //因为要装满,所以先将所有可能置位负无穷,并保留初始状
    dp[0][0]=0;            //让数据只能从初始状态转移
    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
            for(int k=all;k>=sum5[i];k--)
                dp[j][k]=max(dp[j-1][k-sum5[i]]+sum2[i],dp[j][k]);//即为前i个物品,选了j个时的 2的最大个数
    int ans=0;
    for(int i=1;i<=all;i++) ans=max(ans,min(dp[m][i],i)); //答案即为2和5最小值中的最大值
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值