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
",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
",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 }
代码