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;
}
本文介绍了一道计算机科学竞赛题目,涉及动态规划和位运算的应用。作者首先解释了题目背景,指出这并非传统的背包问题,而是一个需要技巧的解题过程。通过计算最小公倍数(LCM)840,作者展示了如何处理数字并构建01背包模型。文章详细阐述了计算冗余量的方法,并利用bitset进行优化,降低了时间复杂度。最后,给出了C++代码实现,展示了解题的完整思路。
231

被折叠的 条评论
为什么被折叠?



