bzoj 1042[HAOI2008]硬币购物 - 背包dp + 容斥原理
1042: [HAOI2008]硬币购物
Time Limit: 10 Sec Memory Limit: 162 MBDescription
硬币购物一共有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
3 2 3 1 10
1000 2 2 2 900
Sample Output
4
27
27
感觉智商收到了侮辱 <+_+>
面值只有四种,但是数量是有限的,所以我们可以用容斥原理
ans = 总的 - 至少一种超出限制 + 至少两种超出限制 - 至少三种超出限制 + 至少四种超出限制
只需要把f预处理就可以了
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #define LL long long 6 7 using namespace std; 8 9 const int MAXS = 1e5; 10 int c[5]; 11 int S; 12 int d[5]; 13 LL f[MAXS + 10]; 14 int tot; 15 inline LL read() 16 { 17 LL x = 0, w = 1; char ch = 0; 18 while(ch < '0' || ch > '9') { 19 if(ch == '-') { 20 w = -1; 21 } 22 ch = getchar(); 23 } 24 while(ch >= '0' && ch <= '9') { 25 x = x * 10 + ch - '0'; 26 ch = getchar(); 27 } 28 return x * w; 29 } 30 31 int num = 0; 32 33 void init() 34 { 35 f[0] = 1; 36 for(int j = 1; j <= 4; j++) { 37 for(int i = 0; i <= MAXS; i++) { 38 if(i >= c[j]) { 39 f[i] += f[i - c[j]]; 40 } 41 } 42 } 43 } 44 45 void cal() 46 { 47 LL ans = 0; 48 for(int i = 0; i < 16; i++) { 49 int num = 1, t = S; 50 for(int j = 1; j <= 4; j++) { 51 if(((1 << (j - 1)) & i) != 0) { 52 num = num * -1; 53 t -= (d[j] + 1) * c[j]; 54 } 55 } 56 //cout<<num<<" "<<i<<" "<<t<<endl; 57 if(t >= 0) { 58 ans = ans + num * f[t]; 59 } 60 } 61 printf("%lld\n", ans); 62 } 63 int main() 64 { 65 for(int i = 1; i <= 4; i++) { 66 c[i] = read(); 67 } 68 init(); 69 tot = read(); 70 while(tot--) { 71 for(int i = 1; i <= 4; i++) { 72 d[i] = read(); 73 } 74 S = read(); 75 cal(); 76 } 77 return 0; 78 } 79 80 /* 81 1 2 5 10 2 82 83 3 2 3 1 10 84 85 1000 2 2 2 900 86 87 */