zoukankan      html  css  js  c++  java
  • 礼物

    2020.10.5

    题目描述

    (n) 个物品,和 (m) 元钱,每个物品有一个价格 (a_i)。现要购买一些物品(每个物品可购买一次),使得在剩下的物品中价格最低的物品也买不了。

    求所有可能的方案个数。 (1leq n,m leq 10^3,1leq a_i leq m)

    解法

    考虑普通的 (0/1) 背包,记 (f_{i,j}) 表示在前 (i) 个数中花费 (j) 元所能得到的购买方案数。

    但直接用这种方式计数,我们并不知道当前剩余物品的最低价格,而如果把其作为状态的话又不好转移。

    换一种思路,考虑枚举这个最小值,那么枚举的这个物品就不能买,小于这个最小值的物品就必须买。那么容易想到讲物品从大到小排序,从前往后枚举这个最小值,在这个最小值位置之后的物品全部加上。用 (m) 减去这个和之后,再考虑用前面那些较大的物品来填充背包,答案累加上背包 ((m-suf-min,m-suf]) 的值。

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    #define N 1007
    #define Mod 1000000007
    
    inline bool Cmp(int x,int y){return x>y;}
    
    long long f[N]={1};
    int n,m,a[N],suf[N];
    int main(){
        freopen("gift.in","r",stdin);
        freopen("gift.out","w",stdout);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+1+n,Cmp);
        for(int i=n;i>=1;i--) suf[i]=suf[i+1]+a[i];
        long long ans=0;
        for(int i=0;i<=n;i++){
            if(i) for(int j=m;j>=a[i];j--)
                f[j]=(f[j-a[i]]+f[j])%Mod;
            if(suf[i+2]>m) continue;
            for(int j=max(m-suf[i+1]+1,0);j<=m-suf[i+2];j++)
                ans=(ans+f[j])%Mod;
        }
        printf("%lld",ans? ans:1);
    }
    
  • 相关阅读:
    菜根谭#250
    菜根谭#249
    菜根谭#248
    [转载]将网卡(设备中断)绑定到特定CPU
    request_mem_region,ioremap 和phys_to_virt()
    [转载]python的range()函数用法
    [转载]Python print函数用法,print 格式化输出
    [转载]python datetime处理时间
    Linux驱动
    Linux驱动
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/13771512.html
Copyright © 2011-2022 走看看