洛谷 P5365 [SNOI2017] 英雄联盟 题解

题目链接

洛谷 P5365 [SNOI2017] 英雄联盟

思路分析

首先,发现 \(M\) 范围很大,但是 \(N\) 的范围摁一下计算器可得大约不超过 \(125\),进而所求的钱数范围大约在 \(2.5\times 10^5\) 以内。结合数据范围,考虑以钱数为背包容量,展示方案数为价值。

考虑英雄,根据乘法原理,总方案数 \(=\) 该英雄皮肤数量(\(\ne 0\)\(\times\) 除该英雄外方案总数。所以,我们考虑分组背包,对于英雄 \(i\),有 \(k_i\) 个皮肤,代价为 \(c_i\),新方案数即为前 \(i-1\) 个英雄的方案数乘上该英雄购买皮肤数 \(j\) 即可。

代码呈现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; // 十年 OI 一场空

const int N=125,M=250010;
int n;
ll m;
int k[N],c[N];
ll dp[M];

int main(){
    scanf("%d%lld",&n,&m);
    for (int i=1;i<=n;++i) scanf("%d",k+i);
    for (int i=1;i<=n;++i) scanf("%d",c+i);
    int t=0;
    for (int i=1;i<=n;++i) t+=k[i]*c[i]; // 钱数上限
    dp[0]=1;
    for (int i=1;i<=n;++i){
        for (int j=t;j>=c[i];--j){
            for (int x=1;x<=k[i] && x*c[i]<=j;++x) dp[j]=max(dp[j],dp[j-c[i]*x]*x);
        }
    }
    for (int i=0;i<=t;++i){
        if (dp[i]>=m){ printf("%d",i);return 0; }
    }
    return 0;
}
posted @ 2026-05-04 22:20  CodingJuRuo  阅读(5)  评论(0)    收藏  举报