首页 > 其他 > 详细

[HAOI2008]硬币购物

时间:2018-10-28 20:22:47      阅读:185      评论:0      收藏:0      [点我收藏+]

Description

BZOJ1042

Solution

一开始以为是4种物品的多重背包计数,感觉好难写啊,就看题解去了。

结果是容斥??

其实不是很难,不考虑个数限制的话就是一个完全背包计数,先预处理出来\(f[i]\)表示\(i\)元花费的完全背包计数。然后每次去掉不合法的,就是\(f[s-c[i]*(d[i]+1)]\),因为如果不合法,某个东西至少拿\(d[i]+1\)个。容斥一下就好了。

Code

const int N = 100010;

ll c[5], n, d[5], s, f[N];

void main() {
    for (int i = 0; i < 4; ++i) c[i] = read();
    f[0] = 1;
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < N; ++j)
            if (j >= c[i]) {
                f[j] += f[j - c[i]];
            }
    n = read();
    while (n--) {
        for (int i = 0; i < 4; ++i) d[i] = read();
        s = read();
        ll ans = 0;
        for (int i = 0; i < 16; ++i) {
            ll cnt = 0, ss = 0;
            for (int j = 0; j < 4; ++j) {
                if (i >> j & 1) cnt++, ss += c[j] * (d[j] + 1);
            }
            if (ss > s) continue;
            if (cnt & 1)
                ans -= f[s - ss];
            else
                ans += f[s - ss];
        }
        printf("%lld\n", ans);
    }
}

Note

物品个数很小的计数问题可以考虑容斥。

[HAOI2008]硬币购物

原文:https://www.cnblogs.com/wyxwyx/p/bzoj1042.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!