1. 程式人生 > 實用技巧 >習題:Round Subset(揹包)

習題: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
*/