bzoj 1042: [HAOI2008]硬币购物
Description
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买s
i的价值的东西。请问每次有多少种付款方法。
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
题解:
正好才讲过容斥,又这题di太大暴力开状态开不了,所以想到了容斥,即合法减不合法
这题就是总状态-超出使用次数的方案数(包括很多种情况)
大概就是:S-一个超出的+两个超出的-三个+四个....共有sigma(C(4,i)) i=1,2,3,4 几种情况
然后就是处理了....我还真不会,于是参考了题解,dfs处理,0/1枚举每一种硬币,然后判断用了几个来确定加和减,
另外不合法方案就是减去di+1个之后的方案....
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 using namespace std; 8 typedef long long ll; 9 const int N=100005; 10 ll c[6],d[6];ll ans=0,f[N]; 11 void dfs(int dep,int s,int k){ 12 if(dep==5){ 13 k%=2; 14 ans+=f[s]*(k%2?-1:1); 15 return ; 16 } 17 if(c[dep]*(d[dep]+1)<=s) 18 dfs(dep+1,s-c[dep]*(d[dep]+1),k+1); 19 dfs(dep+1,s,k); 20 } 21 void work() 22 { 23 int lim=N-5; 24 for(int i=1;i<=4;i++)scanf("%lld",&c[i]); 25 f[0]=1; 26 for(int i=1;i<=4;i++) 27 for(int j=0;j<=lim;j++){ 28 if(j-c[i]>=0) 29 f[j]+=f[j-c[i]]; 30 } 31 int m,sum;scanf("%d",&m); 32 for(int i=1;i<=m;i++){ 33 for(int j=1;j<=4;j++)scanf("%lld",&d[j]); 34 scanf("%d",&sum); 35 ans=0; 36 dfs(1,sum,0); 37 printf("%lld\n",ans); 38 } 39 } 40 int main() 41 { 42 work(); 43 return 0; 44 }