跳转至

容斥原理

不定方程非负整数解计数

\(f(x)\)\(a_0\cdot b_0+a_1\cdot b_1+…a_k\cdot b_k=x\) 的所有方案数,\(a_i\) 为常数,\(b_i\) 为变量

例题

P1450 [HAOI2008] 硬币购物 - 洛谷

先做完全背包处理方案数。

然后二进制枚举,第 \(i\) 枚硬币超过数量限制(恰好用了 \(d[i]+1\) 枚),进行容斥

从而计算出超过数量上限的方案数。

答案为 总方案数减去超过数量的方案数。

代码
C++
using i64 = long long;
i64 f[100005];
int main() {
    f[0] = 1;
    vector<int> c(4);
    for (int i = 0 ; i < 4 ; i++) {
        cin >> c[i];
        for (int j = 0 ; j <= 100000 ; j++) {
            if (j - c[i] >= 0) {
                f[j] += f[j - c[i]];
            }
        }
    }
    int n;
    cin >> n;
    for (int i = 0 ; i < n ; i++) {
        vector<int> d(4);
        i64 s;
        for (int j = 0 ; j < 4 ; j++) {
            cin >> d[j];
        }
        cin >> s;
        i64 res = 0;
        for (int i = 1 ; i < 1 << 4 ; i++) {
            i64 m = s;
            int sign = -1;
            for (int j = 0 ; j < 4 ; j++) {
                if (i & 1 << j) {
                    m -= (d[j] + 1) * c[j];
                    sign = -sign;
                }
            }
            if (m >= 0) {
                res += sign * f[m];
            }
        }
        cout << f[s] - res << "\n";
    }
    return 0;
}