bzoj1042
容斥原理+背包
首先每次做背包是不可行的,那么我们要优化一下,既然是有一些限制条件限制我们获得结果,我们就用容斥去弱化条件,也就是无视一些条件。
既然硬币是有限制的,那么我们就无视限制,用补集求答案,总方案-超限,但是超限也不好算,就用容斥,先跑完全背包求出总方案,然后减去一个超限,加上两个超限,减去三个超限的,加上四个超限的,这样就计算出了总方案,至于怎么计算超限的方案数,我们只要计算f[s-c[i]*(d[i]+1)],因为这样对应体积的方案数加上c[i]*(d[i]+1)的体积就是强制某种物品超限,但是显然这样是有重复的,容斥解决了这个问题。
#include<bits/stdc++.h> using namespace std; const int N = 100010; int tot, s; long long dp[N]; int c[5], d[5]; void ini() { dp[0] = 1; for(int i = 0; i < 4; ++i) for(int j = 1; j <= 100000; ++j) if(j >= c[i]) dp[j] += dp[j - c[i]]; } int main() { for(int i = 0; i < 4; ++i) scanf("%d", &c[i]); scanf("%d", &tot); ini(); while(tot--) { for(int i = 0; i < 4; ++i) scanf("%d", &d[i]); scanf("%d", &s); long long ans = 0; for(int i = 0; i < (1 << 4); ++i) { int t = __builtin_popcount(i) % 2 == 0 ? 1 : -1, sum = s; for(int j = 0; j < 4; ++j) if(i & (1 << j)) sum -= c[j] * (d[j] + 1); ans += sum >= 0 ? (long long)t * dp[sum] : 0; } printf("%lld\n", ans); } return 0; }