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;
}