题目大意

给定\(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. C++ 限定名称查找

    限定名称查找规则实际归纳下来很简单,先对::左边的名称进行查找(遵循,限定,无限定),然后在左边查找到的(此时只查找类型名称)名字的作用域内(含内联名称空间件)查找右边出现的名字,查找到即存在(故可以 ...

  2. C++大数问题

    1.大数的加法 语法:add(char a[],char b[],char s[]); 参数: a[]:被加数,用字符串表示,位数不限 b[]:加数,用字符串表示,位数不限 s[]:结果,用字符串表示 ...

  3. EasyUI取消树节点选中

    $('#organTree').find('.tree-node-selected').removeClass('tree-node-selected'); 取消树的节点选中

  4. JavaScript ES6功能概述(ECMAScript 6和ES2015 +)

    JavaScript在过去几年中发生了很大的变化.这些是您今天可以开始使用的12项新功能! 该语言的新增内容称为ECMAScript 6.它也称为ES6或ES2015 +. 自1995年JavaScr ...

  5. 【PHP】常用的PHP正则表达式收集整理

    匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达式就好办了 匹配双字节字符(包括汉字在内):[^\x00-\xff]评注:可以用来计算字符串的长度 ...

  6. Linux下启动、停止xampp命令

    启动xampp: /opt/lampp/./lampp start 停止xampp: /opt/lampp/./lampp stop 卸载xampp: rm -rf /opt/lampp

  7. (转)iOS静态库与动态库的区别

    一.什么是库? 库是共享程序代码的方式,一般分为静态库和动态库. 静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝. 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用 ...

  8. luogu4169 [Violet]天使玩偶/SJY摆棋子 / bzoj2648 SJY摆棋子 k-d tree

    k-d tree + 重构的思想,就能卡过luogu和bzoj啦orz #include <algorithm> #include <iostream> #include &l ...

  9. centos使用--vsftpd配置

    目录 1 在服务器配置FTP服务 1.1 在root权限下,通过如下命令安装Vsftp(以CentOS系统为例): 1.2 在启动vsftpd服务之前,需要登录云服务器修改配置文件,禁用匿名登录. 1 ...

  10. asp.net中使用ffmpeg

    protected void Button1_Click(object sender, EventArgs e) { string FFmpegArguments = @" -i D:\离歌 ...