P1450 [HAOI2008] 硬币购物

P1450 硬币购物

DP做法显然大家都能想到,但是一看多组数据,凉了。

我一看(s le 10^5) 显然可以预处理出来无限硬币可组成的情况。

那末,我们可以使用容斥做这题(反正只有4种)。

答案看程序。

关于为什么是 (ans - f_{s-c_{i}cdot (d_{i}+1)}) 笔者也想了很久。

愚以为减掉限定第 (i) 种硬币使用 (d_{i}+1) 枚也就直接减掉了 (d_{i}+n) 枚的情况 ((n in N^{+})) 。因为 (f_{s-c_{i} cdot (d_{i} + 1)})(限定使用 (d_{i} + 1) 枚) 是由 (f_{s - c_{i} cdot (d_{i}+2)}) (限定使用 (d_{i}+2)枚) 转移过来的。

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;
const ll MAXN = 5e5+10;

ll N, c[10], d[10], f[MAXN];

int main() {
    for (ll i = 0; i < 4; i++) {
        scanf("%lld", c+i);
    }
    scanf("%lld", &N);
    f[0] = 1;
    for (ll i = 0; i < 4; i++) {
        for (ll j = c[i]; j <= MAXN - 10; j++) {
            f[j] += f[j-c[i]];
        }
    }
    for (ll i = 1; i <= N; i++) {
        for (ll i = 0; i < 4; i++) {
            scanf("%lld", d+i);
        }
        ll s;
        scanf("%lld", &s);
        ll ans = f[s];
        for (ll i = 1; i < (1LL << 4); i++) {
            ll tmp = 0, tim = 0;
            for (ll j = 0; j < 4; j++) {
                if (i & (1LL << j)) {
                    tmp += c[j] * (d[j] + 1);
                    tim++;
                }
            }
            if (s < tmp) continue;
            else {
                if (tim & 1) ans -= f[s - tmp];
                else ans += f[s - tmp];
            }
        }
        printf("%lld
", ans);
    }
    return 0;
}
Yukkuri si te yi te ne
原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13663419.html