bzoj5018: [Snoi2017]英雄联盟

10.5重回bzoj。刷了这道背包DP交了10次。

不过这个真的是一道好题。(也许是我DP太烂

由于钱数较小,容易想到,f[i]表示花了i元所有的展示策略个数。然而在DP的时候却有一个问题,我们枚举买的皮肤个数维护背包时,有可能同一个英雄不同皮肤数叠乘,这样就不对了,所以DP时先从后将更新的位置枚举出来,再枚举买皮肤个数,这样就不会重复。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
LL f[1100000],a[1100],c[1100];
int main()
{
    LL n,m;
    scanf("%lld%lld",&n,&m);
    if(m<=1){printf("0
");return 0;}
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=1;i<=n;i++)scanf("%lld",&c[i]);
    
    memset(f,0,sizeof(f));f[0]=1;
    LL sum=0,ans=2147483647;
    for(int i=1;i<=n;i++)
    {
        if(a[i]<=1)continue;
        sum+=a[i]*c[i];
        for(int j=min(ans,sum);j>=2*c[i];j--)
        {
            for(int k=2;k<=a[i];k++)
            {
                if(k*c[i]>j)break;
                f[j]=max(f[j],f[j-k*c[i]]*k);
            }
            if(f[j]>=m)ans=j;
        }
    }
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/7630799.html