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;
}
View Code

 

posted @ 2017-08-22 22:20  19992147  阅读(182)  评论(0编辑  收藏  举报