今天为什么开坑容斥原理了呢。
因为自己实在是太弱了啊连容斥原理都不会TuT。
硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。
这个嘛。
即求同时满足:
a1<=d1,a2<=d2,a3<=d3,a4<=d4且有∑aici=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=S−⋃i=1nA¯¯¯i
证明?
如果我们考虑 x 在左端没有出现。
那么在右侧我们只需要证明
这个显然的对吧23333
我们考虑 x 在左端出现了,即在任意集合里。
画一下图也知道是对的了吧,因为任意集合的补集都不含有之前的元素。
那么我们可以进行补集转化,将交集转化成并集的形式。
比如有
任意选 - 至少违反一个限制 +至少违反两个 - 至少违反三个+……
任意选后面的是容斥hhh。