1. 程式人生 > >Loj #2256. 「SNOI2017」英雄聯盟

Loj #2256. 「SNOI2017」英雄聯盟

can 最小花費 tps 很多 最小 string loj getchar() ble

題目

我就是個絲薄

如果要用\(dp_i\)表示湊出\(i\)的最小花費顯然不可能的

之後大力猜想能湊出來的狀態不會很多,我的暴力也告訴我不是很多,好像也確實不多的樣子,大概\(4e4\)左右

但是我就這樣思維僵化了,背包套路難道不是看到某一維特別大就把交換一下這一維和\(dp\)值嗎

於是\(dp_i\)表示使用\(i\)的費用湊出的最大的數

分組背包大力轉移即可

代碼

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=150;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,a[maxn],b[maxn],now[maxn];
LL m;
LL dp[2000*150];
int main() {
    n=read();scanf("%lld",&m);
    for(re int i=1;i<=n;i++) a[i]=read();
    for(re int i=1;i<=n;i++) b[i]=read();
    for(re int i=1;i<=n;i++) now[i]=now[i-1]+a[i]*b[i];
    memset(dp,-1,sizeof(dp));
    dp[0]=1;
    for(re int i=1;i<=n;i++) {
        for(re int j=now[i];j;--j)
            for(re int k=2;j-k*b[i]>=0&&k<=a[i];++k)
                dp[j]=max(dp[j],dp[j-k*b[i]]*k);
    }
    for(re int i=0;i<=now[n];i++) 
    if(dp[i]>=m) return printf("%d\n",i),0;
    return 0;
}

Loj #2256. 「SNOI2017」英雄聯盟