zoukankan      html  css  js  c++  java
  • [NOIp模拟赛][01背包] 礼物

    题面

    (T) 要给他的妹妹买礼物。他会不断的买,直到自己身上没有足够的钱来买任何一件礼物为止,他想知道有多少种方案符合他买礼物的方式。

    我们认为两种选择方案不同当且仅当它们选取的的物品的集合不同。

    因为答案可能很大,你只需要输出答案对 (10^7+7) 取模的结果即可。

    共有 (n) 件礼物,价格为 (C_i),小 (T) 持有的钱数为 (m)
    对于 (100%) 的数据,满足 (1 le n le 1000)(1 le m le 1000)(0 le C_i le m)


    这样的统计方案题,如果抛开“必须买到没有钱”这个限制,是可以用 (01) 背包统计方案的:
    (f_i = sum f_{i-C_j}, j in {x | i - x ge 0})

    沿着这个思路想下去,我们可以考虑仍然用这种方式统计方案,然后将对答案有贡献的方案计入答案。

    我们可枚举现在没有选择的价值最小的物品 (i),再枚举一个剩余的钱数 (j),满足 (j lt C_i),这样的答案便是合法的。

    对于 (i) 的枚举,直接排序一遍便可以顺序扫描了。

    代码:

    # include <iostream>
    # include <cstdio>
    # include <algorithm>
    # define MAXN 1005
    # define MAXC 1005
    
    const int MOD = 1e7+7;
    int co[MAXN], f[MAXC];
    
    int main(){
    	int n, m;
    
    	scanf("%d%d", &n, &m);
    
    	int sum = 0;
    	for(int i = 1; i <= n; i++){
    		scanf("%d", &co[i]);
    		sum += co[i];
    	}
    
    	std::sort(co+1, co+n+1);
    
    	int ans = 0; f[0] = 1;
    	if(m >= sum){ // 特判
    		ans = 1;
    	}
    	else{
    		for(int i = n; i >= 1; i--){
    			sum -= co[i];
    
    			for(int j = std::max(0, (m-sum)-(co[i]-1)); j <= m-sum; j++){
    				ans = (ans += f[j]) % MOD;
    			}
    			for(int j = m; j >= co[i]; j--){
    				f[j] = (f[j] + f[j-co[i]]) % MOD;
    			}
    		}
    	}
    
    	printf("%d", ans);
    
    	return 0;
    }
    

    复杂度:(O(nm))

  • 相关阅读:
    冲刺阶段每日站立会议个人博客十二
    冲刺阶段每日站立会议个人博客十一
    针对其他团队建议的反馈
    软件工程概论第五周学习进度条
    冲刺阶段每日站立会议个人博客十
    冲刺阶段每日站立会议个人博客九
    每日站立会议个人博客八
    每日站立会议个人博客七
    软件工程概论第四周学习进度条
    每日站立会议个人博客六
  • 原文地址:https://www.cnblogs.com/Foggy-Forest/p/13719675.html
Copyright © 2011-2022 走看看