[bzoj-5018][Snoi2017]英雄联盟 题解

本文解析了一道类似于背包问题的编程题,通过采用DFSDP的方法,将原问题转化为求在方案数大于等于给定值的情况下最小花费的问题。文章详细介绍了状态转移方程的设计思路,并给出了顺推实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门
题意解析:题目有点像背包,就是给了你n个物品,每个物品有个价格和数量,然后问你在方案数>=m的情况下的最小花费。(方案数是显而易见的每种物品选取的数量之积)


My opinion:题目很明显是一题类似背包的问题,所以当然是 dfs dp了。一开始想到的状态就是f[i][j]表示前i个物品,方案数是j的最小花费,可是这样的话,因为方案数太大,有10^17,先不说MLE,还有TLE。所以我们要换一个状态,我们可以把方案数换成价格,然后存最大的方案数。但是如果我们不节制(不要想歪了),这样方案数还会爆掉long long,然后会发现一个有趣的东西,m是10^17,ki<=10,所以每次如果是m*ki完全不会爆long long,而答案只需要判断答案是否大于等于m,所以每次当方案数大于m时,我们就把方案数改成m。
总结:
1、输入。
2、dp。
3、输出。
……………………实在想不出怎么总结了(dp方程式也特别明显)。


顺推的代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=a;i>=n;i--)
#define Clear(a,x) memset(a,x,sizeof(a))
#define ll long long
#define INF 2000000000
#define eps 1e-8
using namespace std;
ll read(){
    ll x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=125,maxcost=250000;
int n;
int num[maxn],c[maxn];
ll f[maxn][maxcost];
ll m;
int main(){
    n=read(),m=read();
    rep(i,1,n) num[i]=read();
    rep(i,1,n) c[i]=read();
    int sum=0;
    rep(i,1,n)
        sum+=num[i]*c[i];
    f[0][0]=1;
    rep(i,0,n-1)
        rep(j,0,sum)
            rep(k,0,num[i+1])
                f[i+1][j+k*c[i+1]]=min(m,max(f[i+1][j+k*c[i+1]],f[i][j]*(ll)(k==0?1:k)));
    rep(i,0,sum)
        if (f[n][i]>=m){
            printf("%d\n",i);
            return 0;
        }
}

然后这里还有一篇逆推的:
大佬的题解
附上AC记录:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值