第五届新疆省ACM-ICPC程序设计竞赛 H. 虚无的后缀(动态规划+滚动数组优化)

本文介绍了一道算法题的解决方法,题目要求从给定的数字中选择k个数,使它们相乘后的结果末尾0的数量最大化。通过将每个数分解成2和5的因子,并使用动态规划来解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:
链接:https://ac.nowcoder.com/acm/problem/26157

给出 n 个数字,第 i 个数字为 a[i],我们从中选出 k 个数字,使得乘积后缀 0 的个数最多。

思路 :
先把每个数拆分成有多少2和5
然后考虑对这些数跑01背包,每个数里5的个数是花费,2的个数是重量

接下来考虑方程的转移
动态规划 dp[i][j][s]表示前i个数里面拿j个,一共有s个5的时候最多有多少个2

然后考虑dp的转移
当前到第i个数
先考虑不拿这个数
那么就有dp[i][j][s]=dp[i-1][j][s];
然后考虑拿当前这个数
有 dp[i][j][s]=max(dp[i][j][s],dp[i-1][j-1][s-c5[i]]+c2[i]);

最后要注意的初始条件

dp[0][0][0]=0;
dp[1][0][0]=0;

这两个初始条件都不能缺少,否则会错

最后对三维dp改滚动数组
代码如下

#include<bits/stdc++.h>
using namespace  std;
typedef long long ll;
const int maxn = 1e4 + 10;
int c2[222];
int c5[222];
int dp[2][222][maxn];
 int sum=0;


int main()
{
	int n,k;
	ll x;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{

		cin>>x;
		while(x%5==0)x/=5,c5[i]++;
		sum+=c5[i];
		while(x%2==0)x/=2,c2[i]++;
		//printf("%d %d\n",c2[i],c5[i]);

	}
	memset(dp,0xc0,sizeof(dp));
	dp[0][0][0]=0;
	dp[1][0][0]=0;


	for(int i=1;i<=n;i++)
	{

		for(int j=1;j<=min(i,k);j++)
		{

			for(int s=0;s<=sum;s++)
			{
				dp[i&1][j][s]=dp[(i-1)&1][j][s];
				if(s>=c5[i])dp[i&1][j][s]=max(dp[i&1][j][s],dp[(i-1)&1][j-1][s-c5[i]]+c2[i]);
	
			}
		}
	}

	int ans=0;
	for(int i=0;i<=sum;i++)
	{

		ans=max(ans,min(i,dp[n&1][k][i]));
	}

	cout<<ans;


	return 0;
}
/*
4 3
2 5 5 2

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值