BZOJ 1042 HAOI2008 硬币购物

1042: [HAOI2008]硬币购物

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2903  Solved: 1785
[Submit][Status][Discuss]
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
DP预处理+容斥原理。
以前没写过容斥原理,所以这里写下笔记吧。
若用一个01串表示方案种类,第I位为1表示满足D[I]条件,为0表示不满足的话。
那么,我们要求的即是1111。
显然,就是 所有情况(至少有0个0的情况)-至少有一个0的情况+至少有两个0的情况...【减加减加】
即 ANS=0个0=(0个0,1个0,2个0..)-(1个0,2个0,3个0..)+(2个0,3个0..)..
也就是说,减去所有至少偶奇数个0的情况,加上所有至少偶数个0的情况。
这个可以用DFS来做。
每一层即一个位I,可以转移到不受限制的情况(这一位0或1)或者(这一位0)的情况。分别不改颜色和改颜色。
也可以直接循环去枚举
我代码写的是循环去枚举要还是删掉
还是太弱了QAQ
 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 inline ll read(){
 5     ll x=0;ll f=1;char ch=getchar();
 6     while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
 7     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
 8     return x*f;
 9 }
10 ll f[300010]={};
11 int c[5],d[5];
12 namespace zhangenming{
13     void init(){
14          c[1]=read();c[2]=read();c[3]=read();c[4]=read();
15          f[0]=1;
16          for(int i=1;i<=4;i++){
17              for(int j=c[i];j<=200100;j++){
18                  f[j]+=f[j-c[i]];
19             }
20         }
21     }
22     void solve(){
23         ll tot=read();
24         for(int i=1;i<=tot;i++){
25             for(int i=1;i<=4;i++){
26                 d[i]=read();
27             }
28          ll ans=0;
29          ll s=read();
30          if(s>d[1]*c[1]+d[2]*c[2]+d[3]*c[3]+d[4]*c[4]){
31             printf("%lld\n",ans);continue;
32          }
33           ans=f[s];
34           for(ll i=1;i<=4;i++){
35             if(s>=(d[i]+1)*c[i]) ans-=f[s-(d[i]+1)*c[i]];
36           } 
37           for(ll i=1;i<=4;i++){
38               for(ll j=i+1;j<=4;j++){
39                   if(s>=(d[i]+1)*c[i]+(d[j]+1)*c[j]) ans+=f[s-(d[i]+1)*c[i]-(d[j]+1)*c[j]];
40               }
41           }
42          for(ll i=1;i<=4;i++){
43               for(ll j=i+1;j<=4;j++){
44                   for(ll k=j+1;k<=4;k++){
45                       if(s>=(d[i]+1)*c[i]+(d[j]+1)*c[j]+(d[k]+1)*c[k]) ans-=f[s-(d[i]+1)*c[i]-(d[j]+1)*c[j]-(d[k]+1)*c[k]];
46                   }
47               }
48           }
49          if(s>=((d[1]+1)*c[1]+(d[2]+1)*c[2]+(d[3]+1)*c[3]+(d[4]+1)*c[4])){
50             ans+=f[s-(d[1]+1)*c[1]-(d[2]+1)*c[2]-(d[3]+1)*c[3]-(d[4]+1)*c[4]];
51          }
52          
53          printf("%lld\n",ans);
54         }
55     }
56 }
57 int main(){
58     //freopen("A+B.in","r",stdin);
59     //freopen("A+B.out","w",stdout);
60     using namespace zhangenming;
61     init();
62     solve();
63     return 0;
64 }
代码

 

posted @ 2017-11-18 16:40  zhangenming  阅读(148)  评论(0编辑  收藏  举报