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
3 2 3 1 10
1000 2 2 2 900
Sample Output
4
27
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; }