码迷,mamicode.com
首页 > 其他好文 > 详细

[BZOJ 1042] 硬币购物 容斥原理

时间:2017-08-18 23:48:35      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:ret   nbsp   git   lib   原理   这一   for   efi   cst   

题意

  有四种货币, 它们的价值分别是 c[0], c[1], c[2], c[3] .

  n 次询问, 每次给定 d[0], d[1], d[2], d[3], s, 问凑出 s , 且第 i 种货币不超过 c[i] 个的方案数.

  c[i], d[i], s <= 100000 , n <= 1000 .

 

分析

  设第 i 种货币取了 x[i] 个.

  问题转化为求不定方程 c[0]x[0] + c[1]x[1] + c[2]x[2] + c[3]x[3] = s 的非负整数解的个数.

  且满足 4 个限制条件 x[i] <= d[i] .

 

  假如没有使用个数的限制, 我们可以通过背包 DP 进行预处理, f[s] 表示凑出 s 的方案数.

 

  条件取并, 我们尝试用减法原理 + 容斥原理进行转化.

  用 f[s] 减去满足一个 "x[i] > d[i]" 的限制条件的解的个数, 加上满足两个 "x[i] > d[i]" 的限制条件的解的个数, 减去满足三个 "x[i] > d[i]" 的限制条件的解的个数, 加上满足四个 "x[i] > d[i]" 的限制条件的解的个数.

  问题转化为计算满足若干个 "x[i] > d[i]" 的限制条件的解的个数.

  令 x[i] = y[i] + d[i] + 1 , 那么这一项的贡献为 c[i]x[i] = c[i]y[i] + c[i](d[i] + 1) , 令 s 减去 c[i](d[i]+1) , 那么就变成了没有限制使用个数的问题.

 

实现

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 6 #define LL long long
 7 inline int rd(void) {
 8     int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
 9     int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
10 }
11 
12 const int S = 100000;
13 
14 LL c[4], f[S+5];
15 inline LL G(LL n) { return 0 <= n && n <= S ? f[n] : 0; }
16 
17 int main(void) {
18     #ifndef ONLINE_JUDGE
19         freopen("bzoj1042.in", "r", stdin);
20     #endif
21     
22     f[0] = 1;
23     F(i, 0, 3) {
24         c[i] = rd();
25         F(j, c[i], S) f[j] += f[j - c[i]];
26     }
27     
28     int n = rd();
29     F(t, 1, n) {
30         LL d0 = (rd()+1) * c[0], d1 = (rd()+1) * c[1], d2 = (rd()+1) * c[2], d3 = (rd()+1) * c[3], s = rd();
31         LL res = G(s);
32         res = res - G(s - d0) - G(s - d1) - G(s - d2) - G(s - d3);
33         res = res + G(s - d0 - d1) + G(s - d0 - d2) + G(s - d0 - d3) + G(s - d1 - d2) + G(s - d1 - d3) + G(s - d2 - d3);
34         res = res - G(s - d0 - d1 - d2) - G(s - d0 - d1 - d3) - G(s - d0 - d2 - d3) - G(s - d1 - d2 - d3);
35         res = res + G(s - d0 - d1 - d2 - d3);
36         printf("%lld\n", res);
37     }
38     
39     return 0;
40 }

 

[BZOJ 1042] 硬币购物 容斥原理

标签:ret   nbsp   git   lib   原理   这一   for   efi   cst   

原文地址:http://www.cnblogs.com/Sdchr/p/7392437.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!