Bzoj 1042: [HAOI2008]硬币购物 容斥原理,动态规划,背包dp
1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1747 Solved: 1015
[Submit][Status][Discuss]
Description
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。
Input
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s
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
HINT
数据规模
di,s<=100000
tot<=1000
Source
题解:
容斥原理+动态规划
f[i]表示四种硬币个数没有限制的付款方案数。(求f[i]就是个完全背包)
ans=不限定的方案数-(硬币1超过的方案数+硬币2超过的方案数+硬币3超过的方案数+硬币4超过的方案数)+(硬币1,2超过的方案数………………)-(硬币1,2,3超过的方案数)+(硬币1,2,3,4都超过的方案数)
超过的方案数:
例如:要算硬币1超过的方案数,那么我们就要让硬币1超过d[1],即为d[1]+1,则剩余价值为s-(d[1]+1)*c[1]。
具体见程序:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define MAXN 100000 4 #define LL long long 5 LL S,c[6],d[6],f[MAXN+10]; 6 LL read() 7 { 8 LL s=0,fh=1;char ch=getchar(); 9 while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();} 10 while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();} 11 return s*fh; 12 } 13 LL F(LL A,LL B,LL C,LL D) 14 { 15 LL ans=S; 16 if(A!=0)ans-=(d[1]+1)*c[1]; 17 if(B!=0)ans-=(d[2]+1)*c[2]; 18 if(C!=0)ans-=(d[3]+1)*c[3]; 19 if(D!=0)ans-=(d[4]+1)*c[4]; 20 if(ans<0)return 0; 21 return f[ans]; 22 } 23 int main() 24 { 25 LL i,j,sum,tot; 26 for(i=1;i<=4;i++)c[i]=read();tot=read(); 27 f[0]=1; 28 for(i=1;i<=4;i++) 29 { 30 for(j=c[i];j<=MAXN;j++)f[j]+=f[j-c[i]]; 31 } 32 while(tot--) 33 { 34 for(i=1;i<=4;i++)d[i]=read();S=read(); 35 sum=0; 36 sum+=F(0,0,0,0); 37 sum-=F(1,0,0,0); 38 sum-=F(0,1,0,0); 39 sum-=F(0,0,1,0); 40 sum-=F(0,0,0,1); 41 sum+=F(1,1,0,0); 42 sum+=F(1,0,1,0); 43 sum+=F(1,0,0,1); 44 sum+=F(0,1,1,0); 45 sum+=F(0,1,0,1); 46 sum+=F(0,0,1,1); 47 sum-=F(1,1,1,0); 48 sum-=F(1,1,0,1); 49 sum-=F(1,0,1,1); 50 sum-=F(0,1,1,1); 51 sum+=F(1,1,1,1); 52 printf("%lld\n",sum); 53 } 54 return 0; 55 }