codeforces1132E Knapsack

https://codeforces.com/contest/1132/problem/E

本来以为是道大容量背包的,结果是个技巧题。。。

840是1-8的lcm,对于一个840,我们用1-8任意一个数全部填充满是相等的

所以我们先测cnt[1-8]能有多少个840,为了最后搞01背包计算冗余量,我们直接给cnt[1-8]留至少1个840,不超过2个

然后用剩下的数字去做01背包,复杂度就是840*8*840*8*2,这个数并不是很大

然后如果tmp>w,那么说明把tmp直接减少到w/840*840这里,多出来的840是多余的,因为想对应的数字里面至少还剩了一个840

tmp<w,由于剩下的最多只有840*8*2,我们就从min(w-tmp,840*16)向下枚举,看冗余的最大能凑到多少,找到就结束

bitset还可以优化一下01背包,复杂度又除个32,只跑了31ms

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxl=3e5+10;

int n,m,k,cnt,tot,cas;ll w,ans;
ll a[maxl];
bool vis[maxl];
char s[maxl];
bitset <20010> f;

inline void prework()
{
	scanf("%lld",&w);
	for(int i=1;i<=8;i++)
		scanf("%lld",&a[i]);
}

inline void mainwork()
{
	if(w==0){ans=0;return;}
	ll tmp=0;
	for(int i=1;i<=8;i++)
	{
		if(a[i]/(840/i)<2)
			continue;
		tmp+=a[i]/(840/i)-1;
		a[i]%=840/i;
		a[i]+=840/i;
	}
	f[0]=1;
	for(int i=1;i<=8;i++)
		for(int j=1;j<=a[i];j++)
			f|=f<<i;
	if(tmp*840>w)
		tmp=(w/840)*840;
	else
		tmp=tmp*840;
	for(ll j=min(840*16ll,w-tmp);j>=0;j--)
	if(f[j]==1)
	{
		ans=tmp+j;
		break;
	}
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	int t=1;
	//scanf("%d",&t);
	for(cas=1;cas<=t;cas++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/111305617
今日推荐