题目大意

给定\(n\)一颗树,每个点上有一个物品

每个物品有价格\(c[i]\)

有优惠券,能使价格减少\(d[i]\)

但是使用优惠券的前提时购买该物品,且父亲也使用优惠券

给定钱包余额\(lim\)

求最多能买多少物品

\(n\le 5000, c[i],d[i],lim\le 10^9\)

分析

树上背包

由于价值的数字很大,不能用钱来表示状态,个数表示dp值

只能先计算购买\(k\)个的最少价钱,再判断限制

\(f[x][i][0]\)表示\(x\)这个点不用优惠券,子树中买了\(i\)个物品的最低价钱

\(f[x][i][1]\)表示\(x\)这个点不用优惠券,子树中买了\(i\)个物品的最低价钱

使用子树不断合并到当前点的方法,可以使复杂度变为\(n^2\)

(每个点对在贡献一次\(O(1)\)复杂度后合并到一个状态中,相互不会再产生贡献)

做法

记\(x\)为当前点,\(y\)为该点的儿子

边界条件

f[x][0][0]=0 ,f[x][0][1]=INF

f[x][1][0]=c[i], f[x][1][1]=c[i]-d[i]

合并转移(k=i+j)

f[x][k][0]=f[x][i][0]+f[y][j][0]

f[x][k][1]=f[x][i][1]+min(f[y][j][0],f[y][j][1])

实现时会算重(因为是01背包)

法1:枚举和\(k\),逆着扫\(k\),再枚举i或j中的一个

法2:枚举\(i\),逆着扫\(i\),再枚举\(j\)

solution

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int M=5e3+7;
typedef long long LL; inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
} struct vec{
int g[M],te;
struct edge{
int y,nxt;
edge(int _y=0,int _nxt=0){y=_y,nxt=_nxt;}
}e[M<<1];
vec(){memset(g,0,sizeof g);te=0;}
inline void push(int x,int y){e[++te]=edge(y,g[x]);g[x]=te;}
inline void push2(int x,int y){push(x,y);push(y,x);}
inline int& operator () (int x){return g[x];}
inline edge& operator [] (int x){return e[x];}
}e; int n,sz[M];
LL lim,c[M],d[M];
LL f[M][M][2]; void dfs(int x,int fa){
int i,j,k,p,y;
sz[x]=1;
f[x][0][0]=0;
f[x][1][0]=c[x];
f[x][1][1]=c[x]-d[x]; for(p=e(x);p;p=e[p].nxt)
if((y=e[p].y)!=fa){
dfs(y,x); for(k=sz[x]+sz[y];k>=0;k--)
for(j=0;j<=sz[y];j++) if((i=k-j)<=sz[x]){
f[x][k][0]=min(f[x][k][0],f[x][i][0]+f[y][j][0]);
f[x][k][1]=min(f[x][k][1],min(f[x][i][1]+f[y][j][0],f[x][i][1]+f[y][j][1]));
} sz[x]+=sz[y];
}
} int main(){ int i,x;
n=rd(); lim=rd(); for(i=1;i<=n;i++){
c[i]=rd(), d[i]=rd();
if(i>1) e.push(rd(),i);
} memset(f,0x3f,sizeof f);
dfs(1,0); int ans=0;
for(i=0;i<=n;i++) if(min(f[1][i][0],f[1][i][1])<=lim) ans=i;
printf("%d\n",ans); return 0;
}

cf 816E Karen and Supermarket的更多相关文章

  1. 816E. Karen and Supermarket 树形DP

    LINK 题意:给出n个商品,除第一个商品外,所有商品可以选择使用优惠券,但要求其前驱商品已被购买,问消费k以下能买几个不同的商品 思路:题意很明显就是树形DP.对于一个商品有三种选择,买且使用优惠券 ...

  2. CodeForces 816E Karen and Supermarket ——(树形DP)

    题意:有n件商品,每件商品都最多只能被买一次,且有一个原价和一个如果使用优惠券以后可以减少的价格,同时,除了第一件商品以外每件商品都有一个xi属性,表示买这个商品时如果要使用优惠券必须已经使用了xi的 ...

  3. Codeforces 815C Karen and Supermarket 树形dp

    Karen and Supermarket 感觉就是很普通的树形dp. dp[ i ][ 0 ][ u ]表示在 i 这棵子树中选择 u 个且 i 不用优惠券的最小花费. dp[ i ][ 1 ][ ...

  4. CF815C Karen and Supermarket

    题目链接 CF815C Karen and Supermarket 题解 只要在最大化数量的前提下,最小化花费就好了 这个数量枚举ok, dp[i][j][1/0]表示节点i的子树中买了j件商品 i ...

  5. CF815C Karen and Supermarket [树形DP]

    题目传送门 Karen and Supermarket On the way home, Karen decided to stop by the supermarket to buy some gr ...

  6. E. Karen and Supermarket

    E. Karen and Supermarket time limit per test 2 seconds memory limit per test 512 megabytes input sta ...

  7. Codeforces Round #419 (Div. 1) C. Karen and Supermarket 树形DP

    C. Karen and Supermarket     On the way home, Karen decided to stop by the supermarket to buy some g ...

  8. codeforces 815C Karen and Supermarket

    On the way home, Karen decided to stop by the supermarket to buy some groceries. She needs to buy a ...

  9. codeforces round #419 E. Karen and Supermarket

    On the way home, Karen decided to stop by the supermarket to buy some groceries. She needs to buy a ...

随机推荐

  1. 2017年9月22日作业 c++算术运算符 自增 自减 逻辑运算符 位运算符 条件运算符(三元运算符)

    作业1: c++算术运算符试题,分析下面程序的输出结果是什么 //第一个: int x=8999;int value=x*1000/1000; //第二个 int x=8999;int value=x ...

  2. C++ 学习笔记 (八)重载 重写 重定义以及名字覆盖

    学习C++必定会遇到重载.重写.重定义.概念的东西多也是学习C++蛋疼之处,但是还是得弄懂,学懂了也就不觉得多了. 概念,特点: 重载: 直白点说就是函数名字相同,传参的个数,类型不一样.判断标准在于 ...

  3. redis 设置密码验证

    1.找到配置文件:如/etc/redis/redis.conf 2.找到以下内容 # requirepass foobared 3.修改为(redispassword是密码) requirepass ...

  4. (SSO)单点登录原理和总结

    一:什么是单点登录(single Sign-On) SSO 是一种统一认证和授权机制,指访问统一服务器不用应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后, 再访问其他应用中 ...

  5. Fight Against Traffic -简单dijkstra算法使用

    题目链接 http://codeforces.com/contest/954/problem/D 题目大意 n m s t 分别为点的个数, 边的个数,以及两个特殊的点 要求s与t间的距离在新增一条边 ...

  6. 一、Linux 安装

    Linux 安装 本章节我们将为大家介绍Linux的安装. 本章节以 centos6.4 为例. centos 下载地址: 可以去官网下载最新版本:https://www.centos.org/dow ...

  7. docker-compose 使用

    Docker提供一个容器编排工具------>Docker Compose,它允许用户在一个模板(YAML格式)中定义一组相关联的应用容器,这组容器会根据配置模板中的"--link&q ...

  8. 三 python并发编程之多线程-重点

    一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 二 开启线程的两种方式 #方式一 from th ...

  9. Fakeapp 入门教程(1):安装篇!

    在众多AI换脸软件中Fakeapp是流传最广,操作最简单的一款,当然他同样也是源于Deepfakes. 这款软件在设计上确实是花了一些心事,只要稍加点拨,哪怕是再小白的人也能学会.下面我就做一个入门教 ...

  10. jQuery具体实例介绍什么时候用ajax,ajax应该在什么地方使用

    网站开发时,ajax是一个非常方便的工具,它具有和表单相同的功能完成前端和后台之间的交互!它起到局部刷新的功能!那什么时候用ajax呢?下面给大家介绍几个实例,首先应该分为两类:  一.在用表单和aj ...