傳送門c++
根據容斥原理spa
其中\(S_i\)表示第\(i\)種元素超限的取的方法集合,交的初始值是\(U\)。(\(U\)表全集,\(\overline A\)表\(A\)在\(U\)下的補集)code
如何求出\(\left|\bigcap_{j=1}^k S_{i_j}\right|\)?
考慮先求出徹底揹包的dp值
而後強制將第\(i_j\)個元素選取超過\(d_{i_j}\)個。
這樣的方案總數爲\(dp[t]-dp[t-\sum_{j=1}^k(d_i+1)c_i]\)。(\(dp[]\)的負數項爲\(0\))ci
而後就能夠愉快地容斥了。get
#include <bits/stdc++.h> using namespace std; const int n = 4, mx = 1e5+10, pm[] = {1,-1}; #define int long long int c[n], d[n], dp[mx] = {1}; signed main() { for (int i = 0; i < 4; ++i) { cin >> c[i]; for (int j = c[i]; j < mx; ++j) dp[j] += dp[j-c[i]]; } int tot, s; cin >> tot; while (tot--) { for (int i = 0; i < 4; ++i) cin >> d[i]; cin >> s; int res = 0; for (int i = 0; i < 16; ++i) { int tmp = s, cnt = 0; for (int j = 0; j < 4; ++j) { if ((i>>j) & 1) { cnt++; tmp -= (d[j]+1)*c[j]; } } // cout << cnt << ' ' << tmp << endl; res += pm[cnt%2]*(tmp>=0?dp[tmp]:0); } cout << res << endl; } }