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

Sample Output

4
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 }

 

posted @ 2017-08-10 18:24  PIPIBoss  阅读(...)  评论(... 编辑 收藏