容斥原理

今天为什么开坑容斥原理了呢。
因为自己实在是太弱了啊连容斥原理都不会TuT。
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。
这个嘛。


即求同时满足:
a1<=d1,a2<=d2,a3<=d3,a4<=d4aici=s
这个好像不太好求?
我们注意到这个东西是交集啊。
这个东西等于至少都不违反 - 至少违反一个 + 至少违反两个 - 至少违反三个 + 至少违反四个。

//bzoj 1042
#include<bits/stdc++.h>
#define Rep(i,n) for(int i = 1;i <= n;i ++)
using namespace std;
int m,n,d[5],c[5];
long long f[100005],ans;
void dfs(int x,int y,int sum)
{
    if(sum < 0)return;
    if(x == 5)
    {
        y & 1 ? ans -= f[sum] : ans += f[sum];
        return ;
    }
    dfs(x + 1,y + 1,sum - (d[x] + 1) * c[x]);
    dfs(x + 1,y,sum);
}
int main ()
{
    int T;
    scanf("%d%d%d%d%d",&c[1],&c[2],&c[3],&c[4],&T);
    f[0] = 1;
    Rep(i,4)for(int j = c[i];j <= 100000; ++ j)f[j] += f[j - c[i]];
    while(T --)
    {
        ans = 0;
        int s;
        scanf("%d%d%d%d%d",&d[1],&d[2],&d[3],&d[4],&s);
        dfs(1,0,s);
        printf("%lld\n",ans);
    }
    return 0;
}

我们注意到,容斥原理可以把交集形式转化成并集形式。
理由是这样的:

i=1nAi=Si=1nA¯¯¯i

证明?
如果我们考虑 x 在左端没有出现。
那么在右侧我们只需要证明x在并集部分出现次数为1。
这个显然的对吧23333
我们考虑 x 在左端出现了,即在任意集合里。
画一下图也知道是对的了吧,因为任意集合的补集都不含有之前的元素。
那么我们可以进行补集转化,将交集转化成并集的形式。
比如有n个限制,那么我们就可以把问题变成:
任意选 - 至少违反一个限制 +至少违反两个 - 至少违反三个+……
任意选后面的是容斥hhh。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值