zoukankan      html  css  js  c++  java
  • CF816E-Karen and Supermarket

    题目

    Description

    今天Karen要去买东西。

    一共有 (n) 件物品,每件物品的价格为(c_i),同时每件物品都有一张优惠券,可以对这件物品减价 (d_i) . 使用第 (i) 件物品的优惠券的条件是买这件物品并且使用了第 (x_i) 张优惠券。现在给出Karen带的钱数 (b) ,问最多能买几件物品。

    Input

    第一行两个整数 (nle 5 imes 10^3 , ble 10^9)

    接下来 (n) 行中第 (i) 行,首先有两个整数 (c_i,d_ile 10^9) 。对于 (i>1) 有第三个整数 (1le x_i<i)

    Output

    一行,输出最多能买的物品个数。

    Sample Input

    样例1:
    6 16
    10 9
    10 5 1
    12 2 1
    20 18 3
    10 2 3
    2 1 5

    样例2:
    5 10
    3 1
    3 1 1
    3 1 2
    3 1 3
    3 1 4

    Sample Output

    样例1:
    4

    样例2:
    5

    Hint

    样例1: 买1,3,4号物品,用优惠券;买6号物品,不用优惠券

    样例2:买所有的的物品,用优惠券

    分析

    由于每个物品只有一件,我们可以把问题转化成求买 (k) 个物品至少需要多少钱,最后再统计最多可以买多少个。

    由于有 (1le x_i<i) ,所以优惠券的使用条件构成了一棵树。现在问题是如何在这颗树上求解。

    注意到如果一个点不用优惠券,那么子树中所有点都不能用,所以设状态:

    (f[x][i][0,1]) 表示以 (x) 为根的子树中买 (i) 件物品,是否可以用优惠券(0不能,1能),那么可以通过子树的信息来更新当前点:

    [f[x][i+j][0]=min {f[u][i][0]+f[v][j][0],u,vin ext{subtree}(x)} \ f[x][i+j][1]=min {f[u][i][1]+f[v][j][1],f[u][i][0]+f[v][j][1],u,vin ext{subtree}(x)} \ ]

    即如果当前点不可用优惠券,那么子树都不能用。如果当前点用优惠券,那么子树可用可不用。

    这样(f[ ext{root}][k][1])就是我们要求的东西。

    这样做似乎是(O(n^3))的呢!我们实际上是枚举子树中的点对,所以可以不断地把点合并进当前点中,就可以做到(n^2)级别了。

    循环的时候要从后往前,否则无法保证每件物品只买一次。

    代码

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<algorithm>
    using namespace std;
    typedef long long giant;
    int read() {
    	int x=0,f=1;
    	char c=getchar();
    	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    const int maxn=5e3+10;
    const giant inf=1e13;
    int n,bud;
    giant f[maxn][maxn][2];
    vector<int> g[maxn];
    void add(int x,int y) {g[x].push_back(y);}
    void Min(giant &x,giant y) {x=min(x,y);}
    int dfs(int x) {
    	int sz=1;
    	for (int v:g[x]) {
    		int vs=dfs(v);
    		for (int j=sz;j>=0;--j) {
    			for (int i=vs;i>=0;--i) {
    				Min(f[x][i+j][0],f[x][j][0]+f[v][i][0]);
    				Min(f[x][i+j][1],f[x][j][1]+f[v][i][1]);
    			}
    		}
    		sz+=vs;
    	}
    	for (int i=0;i<=n;++i) Min(f[x][i][1],f[x][i][0]);
    	return sz;
    }
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	n=read(),bud=read();
    	for (int i=1;i<=n;++i) for (int j=0;j<=n;++j) for (int k=0;k<2;++k) f[i][j][k]=inf;
    	for (int i=1;i<=n;++i) {
    		f[i][0][0]=0,f[i][1][0]=read(),f[i][1][1]=f[i][1][0]-read();
    		if (i>1) add(read(),i);
    	}
    	dfs(1);
    	int ans=0;
    	for (int i=1;i<=n;++i) if (f[1][i][1]<=bud) ans=i;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Pieczęć(模拟)
    【并查集】关押罪犯
    火车进栈
    独木舟上的旅行
    哈尔滨理工大学第八届程序设计团队赛K题
    [数学、递推]Everything Is Generated In Equal Probability
    [构造]triples I
    2019牛客第三场
    [DP]销售
    [哈夫曼树]猜球球
  • 原文地址:https://www.cnblogs.com/owenyu/p/7140734.html
Copyright © 2011-2022 走看看