luogu P1450 [HAOI2008]硬币购物
题目大意比较清楚
题解
这题正向做不是很好做
考虑求问题的补集
求不合法的方案数,
发现可以用容斥来解决
然后用总的方案数减去不合法的即可
先做一个完全背包
f
[
1...100000
]
f[1...100000]
f[1...100000]
假设当前硬币的面值是
a
[
i
]
a[i]
a[i],个数限制是
g
s
[
i
]
gs[i]
gs[i]个
然后不合法的方案数就是
f
[
s
−
a
[
i
]
∗
(
g
s
[
i
]
+
1
)
]
f[s - a[i] *(gs[i] +1)]
f[s−a[i]∗(gs[i]+1)]
然后再做容斥就可以了
具体看代码吧
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[15], gs[15], f[200005], n, t;
signed main(){
scanf("%lld%lld%lld%lld%lld", &a[1], &a[2], &a[3], &a[4], &t);
f[0] = 1;
for(int j = 1; j <= 4; j ++)
for(int i = 0; i <= 100000; i ++)
f[i + a[j]] += f[i];//先做一个完全背包
while(t --){
scanf("%lld%lld%lld%lld%lld", &gs[1], &gs[2], &gs[3], &gs[4], &n);
int ans = f[n];
for(int i = 1; i < (1 << 4); i ++){
int o = 1, oo = 0;
for(int j = 1; j <= 4; j ++) if(i & (1 << (j - 1))) o = - o, oo += (long long)(gs[j] + 1) * a[j];//容斥
if(oo <= n) ans += o * f[n - oo];//容斥
}
printf("%lld\n", ans);
}
return 0;
}
我觉得我需要智力康复一下QWQ