【倍增dp】P3462 [POI2007]ODW-Weights

由于砝码质量成倍数,那么就可以把所有的盒子拆分成进制的形式,比如有1、2、4的砝码,那么容量为9的容器就写成(2,0,1)。把所有盒子的进制数组相加,累计每个进制位能放的数量。

计算答案时,我们可以贪心的考虑,由小到大放砝码更优,对于每一个砝码,找到其重量对应的进制,如果进制位上有值,直接加入即可;如果没有,找到其前方距离它最近的有值的进制,如果找不到,输出答案结束程序。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=100001;
int a[maxn],box[maxn],n,m,aa[maxn],ans,k,cnt,flag=1,f[33];
bool cmp(int a,int b)
{
	return a>b;
}
int main() 
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&box[i]);
	for(int i=1;i<=m;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+m,cmp);
	for(int i=1;i<=m;i++)
		if(a[i]!=a[i-1])
			aa[++cnt]=a[i];//去重 
	for(int i=1;i<=n;i++)
		for(int k=1;k<=cnt;k++)
		{
			f[k]+=box[i]/aa[k]; 
			box[i]%=aa[k];
		}//将容器拆分成进制 
	f[0]=1;
	sort(a+1,a+1+m);
	for(int i=1;i<=m;i++)
	{
		int x=a[i];
		for(int j=cnt;j>=1;j--)
		{
			if(aa[j]<x) continue;
			for(k=j;k>=0 && !f[k];k--);
			if(!k)
			{
				printf("%d\n",ans);
				return 0;
			}
			for(int p=k;p<j;p++)
				f[p]--,f[p+1]+=aa[p]/aa[p+1];
			f[j]--;
			ans++;
			break;
		}
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/andyc_03/article/details/107764805