BZOJ1042: [HAOI2008]硬币购物

Description

  硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次

带di枚ci硬币,买s的价值的东西。请问每次有多少种付款方法。

Input

  第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000

Output

  每次的方法数

Sample Input

1 2 5 10 2
3 2 3 1 10
1000 2 2 2 900

Sample Output

4
27
 
题目大意:
容量为s的背包。每个物品的体积ci和数量si,求有多少种
方案将背包正好填满。
 
题解:dp预处理+容斥原理
预处理出没有数量限制下的方案数,再容斥减去超过物品数量的方案数
总的方案数-一个物品超出限制的方案数+两个物品超出限制的方案数-三个物品超出
限制的方案数+4个物品超出限制的方案数。
 
代码:
#include<iostream>
#include<cstdio>
using namespace std;

int tot,sum;
int c[7],d[7];
long long ans,f[100009];

void dfs(int now,int cnt,int sum){
    if(now==5){
        if(cnt&1)ans-=f[sum];
         else ans+=f[sum];
        return;
    }
    dfs(now+1,cnt,sum);
    if(sum-(d[now]+1)*c[now]>=0)
    dfs(now+1,cnt+1,sum-(d[now]+1)*c[now]);
}

int main(){
    scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&tot);
    f[0]=1;
    for(int i=1;i<=4;i++)
     for(int j=c[i];j<=100000;j++)
      f[j]+=f[j-c[i]];
    for(int i=1;i<=tot;i++){
        ans=0;
        scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&sum);
        dfs(1,0,sum);
        cout<<ans<<endl;
    }
    return 0;
}

 

posted @ 2017-10-10 15:14  xun薰  阅读(...)  评论(... 编辑 收藏