习题:Round Subset(背包)

题目

传送门

思路

考虑如果末尾是0,那么一定是一个2和一个5组合起来

之后就是背包的板子了

这里有一个小优化,第二位考虑5的数量而不是2的数量

代码

#include<iostream>
#include<cstring>
using namespace std;
int dp[2][205][5155];//滚动,选了j个数,有k个5,最大能选出的2
int n,m,ans;
int cnt2[205],cnt5[205],limit;
int la,now;
void divide(long long val,int _ind)
{
	if(val==0)
		return;
	while(val%2==0)
	{
		cnt2[_ind]++;
		val/=2;
	}
	while(val%5==0)
	{
		cnt5[_ind]++;
		val/=5;
	}
	limit+=cnt5[_ind];
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		long long val;
		cin>>val;
		divide(val,i);
	}
	//for(int i=1;i<=n;i++)
	//	cout<<cnt2[i]<<' '<<cnt5[i]<<endl;
	memset(dp,-1,sizeof(dp));
	la=0,now=1;
	dp[1][0][0]=0;
	dp[0][0][0]=0;
	for(int i=1;i<=n;i++)
	{
		la=now;
		now^=1;
		for(int j=1;j<=min(i,m);j++)
		{
			for(int k=0;k<=limit;k++)
			{
				dp[now][j][k]=dp[la][j][k];
				if(k<cnt5[i])
					continue;
				if(dp[la][j-1][k-cnt5[i]]!=-1)
				{
					dp[now][j][k]=max(dp[la][j][k],dp[la][j-1][k-cnt5[i]]+cnt2[i]);
					if(j==m)
						ans=max(ans,min(dp[now][j][k],k));
				}
			}
		}
	}
	cout<<ans;
	return 0;
}
/*
3 1
1000000000000000000 800000000000000000 625
*/
posted @ 2020-08-24 19:10  loney_s  阅读(102)  评论(0)    收藏  举报