bzoj 1042

典型的背包+容斥

首先,考虑如果没有个数的限制,那么就是一个完全背包,所以先跑一个完全背包,求出没有个数限制的方案数即可

接下来,如果有个数的限制,那么我们就要利用一些容斥的思想:没有1个超过限制的方案=至少0个超过限制-至少1个超过限制+至少2个超过限制-至少3个超过限制+至少4个超过限制

所以我们用2进制数枚举谁超过了限制,然后加入上面的容斥即可

其中:如果第i种硬币的限制为ni,那么如果i要求超过限制,那么至少要用ni+1个,所以i超过限制的方案数为f[s-(ni+1)ci](f[s]为全方案数)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
ll dp[100005];
int c[5];
int l[5];
int q;
int cot(int sit)
{
    int cnt=0;
    if(sit&1)
    {
        cnt++;
    }
    if(sit&2)
    {
        cnt++;
    }
    if(sit&4)
    {
        cnt++;
    }
    if(sit&8)
    {
        cnt++;
    }
    return cnt;
}
int main()
{
    for(int i=1;i<=4;i++)
    {
        scanf("%d",&c[i]);
    }
    dp[0]=1;
    for(int j=1;j<=4;j++)
    {
        for(int i=1;i<=100000;i++)
        {
            if(i>=c[j])
            {
                dp[i]+=dp[i-c[j]];
            }
        }
    }
    scanf("%d",&q);
    while(q--)
    {
        for(int i=1;i<=4;i++)
        {
            scanf("%d",&l[i]);
        }
        int s;
        scanf("%d",&s);
        ll ans=0;
        for(int i=0;i<16;i++)
        {
            int temp=s;
            if(cot(i)&1)
            {
                for(int j=0;j<4;j++)
                {
                    if((1<<j)&i)
                    {
                        temp-=(l[j+1]+1)*c[j+1];
                    }
                }
                if(temp<0)
                {
                    continue;
                }else
                {
                    ans-=dp[temp];
                }
            }else
            {
                for(int j=0;j<4;j++)
                {
                    if((1<<j)&i)
                    {
                        temp-=(l[j+1]+1)*c[j+1];
                    }
                }
                if(temp<0)
                {
                    continue;
                }else
                {
                    ans+=dp[temp];
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2018-11-06 07:40  lleozhang  Views(135)  Comments(0Edit  收藏  举报
levels of contents