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
 
我们可以先不要求硬币的个数,求一下背包。。。
然后我们用一下容斥原理。。。
对于s,我们如果不限制则是f[s]种方案。。
如果第一种硬币放多了也能达到s,则是f[s-(d1+1)*s1]
同理,可以求出第二种到第四种。。。
然后我们会发现我们减多了。。
所以要加上,第一种和第二种都放多了的情况。。。
同理。。。
然后我们又发现我们又加多了。。
所以要减去第一种,第二种,第三种都放多的情况。。
同理。。。
最后我们又发现我们减多了。。。
所以再加上四种硬币都放多的情况。。。
 1 #include<iostream>
 2 #include<cstdlib>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<algorithm>
 7 #include<string>
 8 #include<map>
 9 #include<queue>
10 #include<vector>
11 #include<set>
12 #define inf 1000000000
13 #define maxn 100000+5
14 #define maxm 10000+5
15 #define eps 1e-10
16 #define ll long long
17 #define for0(i,n) for(int i=0;i<=(n);i++)
18 #define for1(i,n) for(int i=1;i<=(n);i++)
19 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
20 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)
22 using namespace std;
23 int read(){
24     int x=0,f=1;char ch=getchar();
25     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
26     while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();}
27     return x*f;
28 }
29 int a[5],d[5];
30 ll f[maxn],ans;
31 ll find(int a){
32     if(a>=0)return f[a];
33     else return 0;
34 }
35 int main(){
36     //freopen("input.txt","r",stdin);
37     //freopen("output.txt","w",stdout);
38     for1(i,4)a[i]=read();
39     int tot=read();
40     f[0]=1;
41     for1(i,4)
42         for1(j,100000)
43             if(j-a[i]>=0)
44                 f[j]+=f[j-a[i]];
45     for1(i,tot){
46         for1(j,4)d[j]=read();
47         int s=read();
48         ans=find(s);
49         for1(j,4)
50             ans-=find(s-(d[j]+1)*a[j]);
51         for1(j,4)
52             for(int k=j+1;k<=4;k++)
53                 ans+=find(s-(d[j]+1)*a[j]-(d[k]+1)*a[k]);
54         for1(j,4)
55             for(int k=j+1;k<=4;k++)
56                 for(int t=k+1;t<=4;t++)
57                     ans-=find(s-(d[j]+1)*a[j]-(d[k]+1)*a[k]-(d[t]+1)*a[t]);
58         for1(j,4)
59             s-=(d[j]+1)*a[j];
60         ans+=find(s);
61         printf("%lld\n",ans);
62     }
63     return 0;
64 }
View Code

 

posted @ 2016-05-18 20:46  HTWX  阅读(123)  评论(0编辑  收藏  举报