JZOJ 2059J. 稀有逛超市

题目

题目描述

【题目背景】
众所周知,机房里有三个人,一个是 THU 的,一个是 PKU 的,最弱的是 FDU 的。稀有就 是那个 FDU 的„稀有特别喜欢吃东西,但是又喜欢打游戏„结果就忙得不可开交„
【问题描述】
稀有打算去超市买点东西,他身上共有 N 元钱,其中 K 元钱都是准备用来买游戏打的, 因此十分蛋疼的就是剩下的钱安排买什么了。超市的每件东西有很多类,第一类只有价格和 给稀有带来的愉悦值,但是每种只有一件;第二类每种有无数件,同样有价格和愉悦值;其 他类除了每一种有价格和愉悦值之外,每一类一共只能取一件。(我会告诉你稀有去了 HZ 之后身上没钱了?)

输入

输入文件 shop.in 共有 M+1 行。
第一行包含三个整数,N,K,M,N,K 如题意,M 为东西个数。
第二至 M+1 行包含三个正整数,分别表示价格 Pi,愉悦值 Wi,属于哪一类 Ci。

输出

输出文件 shop.out 只有一行,最大愉悦值。

样例输入

100 70 2
31 1000 1
30 2 2

样例输出

2
样例解释:买第二件啊!只买得起第二件了啊!有木有!!坑爹啊,愉悦值只有 2 啊!!

数据范围限制

对于 50%的数据,只含前两类物品。
对于 100%的数据,K<=N<=20000,M<=1000,|Wi|<=10000,|Pi|<=10000。
最多一共有 1000 类物品,类型最大为第 1000 类。

题解

这题显然是3个背包嘛。第一类的01背包,第二类的无限背包。
这样可以拿50分。
至于第三个背包,我们知道同一类物品最多只能够选一个,所以我们要在每一类物品中选最优的那一个。

F[j]=max(F[ja[k].p]+a[k].w)

(a>2,a[k].c(c))

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 20010
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note
{
    int p,w,c;
};
note a1[N],a2[N],a3[N];
bool cmp(note x,note y)
{
    return x.c<y.c;
}
int f[N],i,j,k,last,n,m,ans,x,y,z,_1,_2,_3;
int main()
{
    freopen("shop.in","r",stdin);
    freopen("shop.out","w",stdout);
    scanf("%d%d%d",&n,&k,&m);
    n-=k;
    fo(i,1,m)
    {
        scanf("%d%d%d",&x,&y,&z);
        if (z==1) a1[++_1].p=x,a1[_1].w=y,a1[_1].c=z;else
        if (z==2) a2[++_2].p=x,a2[_2].w=y,a2[_2].c=z;else
        a3[++_3].p=x,a3[_3].w=y,a3[_3].c=z;
    }
    fo(i,1,_1)
        fd(j,n,a1[i].p)
            f[j]=max(f[j],f[j-a1[i].p]+a1[i].w);
    fo(i,1,_2)
        fo(j,a2[i].p,n)
            f[j]=max(f[j],f[j-a2[i].p]+a2[i].w);
    sort(a3+1,a3+_3+1,cmp);
    last=1;
    fo(i,1,_3)
        if (a3[i].c!=a3[i+1].c)
        {
            int mn=2147483647;
            fo(k,last,i) mn=min(mn,a3[k].p);
            fd(j,n,mn)
                fo(k,last,i)
                    if (a3[k].p<=j)
                        f[j]=max(f[j],f[j-a3[k].p]+a3[k].w);
            last=i+1;
        }
    fo(i,0,n) ans=max(ans,f[i]);
    printf("%d",ans);
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值