题面
题意:4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。
每次带di枚ci硬币,买价值s,问多少种付款方法。
若没有限制,就是一个完全背包的计数。
额,考虑容斥,直观说来就是
ans=没限制的方案数-1种硬币超限的方案数+2种硬币超限的方案数-3种硬币超限的方案数+4种硬币超限的方案数
写成柿子有
f[S]=∑T⊇Sg[T]⇒g[S]=∑T⊇S(−1)|T|−|S|f[T]
f[S]为S中的硬币超出了限制的方案数,g[S]为只有 S中的硬币超出限制的方案数。
ans=g[0]。
f[S]为S中的硬币都选了b+1个,剩下的钱随便选的方案。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
int n,a[5];
LL f[100100];
int s,b[5];
LL work(int x)
{
LL re=1;
while(x)
{
x-=(x&-x);
re=-re;
}
return re;
}
int main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
for(int i=0;i<=3;i++)
cin>>a[i];
cin>>n;
f[0]=1;
for(int i=0;i<=3;i++)
for(int j=a[i];j<=100000;j++)
f[j]+=f[j-a[i]];
while(n--)
{
LL ans=0;
for(int i=0;i<=3;i++)
scanf("%d",&b[i]);
scanf("%d",&s);
for(int i=0;i<=15;i++)
{
int rest=s;
for(int j=0;j<=3;j++)
if(i&(1<<j))
rest-=(b[j]+1)*a[j];
if(rest<0)
continue;
ans+=f[rest]*work(i);
}
printf("%lld\n",ans);
}
return 0;
}