[HAOI2008]硬币购物

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

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

posted @ 2018-10-28 19:08  wyxwyx  阅读(159)  评论(0编辑  收藏  举报