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

题目传送门
题意解析:题目有点像背包,就是给了你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
#include
#include
#include
#include
#include
#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记录:
这里写图片描述

你可能感兴趣的:(bzoj,dp)