bzoj 1042: [HAOI2008]硬币购物

神奇的容斥 什么都能干

/**************************************************************
    Problem: 1042
    User: lxy8584099
    Language: C++
    Result: Accepted
    Time:44 ms
    Memory:1604 kb
****************************************************************/
 
/*
    容斥
    先算出每个都不限制的背包
    然后对于一个di限制 其他都不限制 个数就是 f[s-ci*(di+1)] 
    对于容斥 奇减偶加 
*/
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=1e5+50;
int c[5],tot;
ll f[N];
int d[5],s;
int F(int x)
{
    return c[x]*(d[x]+1);
}
int main()
{
    scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&tot);
    f[0]=1;
    for(int i=1;i<=4;i++)
        for(int j=c[i];j<=100000;j++)
            f[j]+=f[j-c[i]];
    while(tot--)
    {
        scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&s);
        ll ans=f[s];
        if(s-F(1)>=0) ans-=f[s-F(1)];
        if(s-F(2)>=0) ans-=f[s-F(2)];
        if(s-F(3)>=0) ans-=f[s-F(3)];
        if(s-F(4)>=0) ans-=f[s-F(4)];
        if(s-F(1)-F(2)>=0) ans+=f[s-F(1)-F(2)];
        if(s-F(1)-F(3)>=0) ans+=f[s-F(1)-F(3)];
        if(s-F(1)-F(4)>=0) ans+=f[s-F(1)-F(4)];
        if(s-F(3)-F(2)>=0) ans+=f[s-F(3)-F(2)];
        if(s-F(4)-F(2)>=0) ans+=f[s-F(4)-F(2)];
        if(s-F(3)-F(4)>=0) ans+=f[s-F(3)-F(4)];
        if(s-F(1)-F(2)-F(3)>=0) ans-=f[s-F(1)-F(2)-F(3)];
        if(s-F(1)-F(2)-F(4)>=0) ans-=f[s-F(1)-F(2)-F(4)];
        if(s-F(4)-F(2)-F(3)>=0) ans-=f[s-F(4)-F(2)-F(3)];
        if(s-F(1)-F(3)-F(4)>=0) ans-=f[s-F(1)-F(3)-F(4)];
        if(s-F(1)-F(2)-F(3)-F(4)>=0) ans+=f[s-F(1)-F(2)-F(3)-F(4)];
        printf("%lld\n",ans);
    }
     
     
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lxy8584099/p/10296409.html