CF815C Karen and Supermarket

题目链接

CF815C Karen and Supermarket

题解

只要在最大化数量的前提下,最小化花费就好了
这个数量枚举ok,
dp[i][j][1/0]表示节点i的子树中买了j件商品 i 优惠了 / 没优惠
复杂度是n^2的
因为每次是新儿子节点的siz * 之前儿子几点的siz,
就相当于树上的节点两两匹配,这个匹配只会在lca处计算一次

代码

#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#define LL long long 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c  > '9') { if(c == '-')f = -1; c = getchar(); } 
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
const int maxn = 5007; 
int n; LL b;int c[maxn], d[maxn]; 
struct node {
    int v,nxt; 
} edge[maxn]; 
int head[maxn],num = 0 ;  
inline void add_edge(int u,int v) { 
    edge[++ num].v = v; edge[num].nxt = head[u];head[u] = num; 
}  
LL dp[maxn][maxn][2]; 
int siz[maxn]; 
void dfs(int x) { 
    siz[x] = 1;
    dp[x][0][0] = 0; 
    dp[x][1][0] = c[x] ; 
    dp[x][1][1] = c[x] - d[x]; 
    //for(int i = head[x];i;i = edge[i].nxt)  dfs(edge[i].v),  siz[x] += siz[edge[i].v]; 
    for(int i = head[x];i;i = edge[i].nxt) { 
        int v = edge[i].v; 
        dfs(v); 
        for(int j = siz[x];j >= 0;-- j) { 
            for(int k = 0;k <= siz[v];++ k) {  
                dp[x][j + k][0] = std::min(dp[x][j + k][0],dp[x][j][0] + dp[v][k][0]); 
                dp[x][j + k][1] = std::min(dp[x][j + k][1],dp[x][j][1] + std::min(dp[v][k][1],dp[v][k][0])); 
            } 
        } siz[x] += siz[v]; 
    } 
} 
int main() {  
    memset(dp,0x3f,sizeof dp); 
    n = read(), b = read(); 
    c[1] = read();  d[1] = read(); 
    for(int pre, i = 2;i <= n;++ i) { 
        c[i] = read(),d[i] = read(); pre = read(); 
        add_edge(pre,i); 
    } 
    dfs(1); 
    int ans = 0; 
    for(int i = 1;i <= n;++ i) 
        if(std::min(dp[1][i][0],dp[1][i][1]) <= b)ans = i;   
    printf("%d\n",ans); 
    return 0; 
} 
  

转载于:https://www.cnblogs.com/sssy/p/9445684.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值