版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
不定方程非负整数解:,
对于表示的解的数目。
有的下界大于0,我们可以同时减掉这个下界,使下界都为0。
那么的不定方程形式为,这个长度为 k 的 a 数组相当于在枚举子集。
HAOI 2008:有4种不同的硬币c[i],每种硬币都有一定的数量上限d[i],买价值为S的物品,一共有多少种付款方式。实际上就是求解有限制的不定方程 非负整数解的个数。
等价于求解:
二进制枚举子集
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
typedef long long ll;
ll c[5], d[5], tot, S, f[maxn];
int main()
{
scanf("%lld %lld %lld %lld %lld", &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 < maxn; j++) f[j] += f[j - c[i]];
}
while(tot--) {
scanf("%lld %lld %lld %lld %lld", &d[1], &d[2], &d[3], &d[4], &S);
ll ans = 0;
for(int i = 1; i < 16; i++) { // 二进制枚举子集 买还是不买
ll m = S, bit = 0;
for(int j = 1; j <= 4; j++) { // 超出限制d[j] + 1,剩下的随便买
if(i >> (j - 1) & 1) m -= (d[j] + 1) * c[j], bit++;
}
if(m >= 0) ans += (bit % 2 * 2 - 1) * f[m]; // 容斥
}
printf("%lld\n", f[S] - ans);
}
return 0;
}
dfs 枚举
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
typedef long long ll;
ll d[5], c[5], tot, S, f[maxn], ans;
void init()
{
f[0] = 1;
for(ll i = 1; i <= 4; i++) {
for(ll j = c[i]; j < maxn; j++) f[j] += f[j - c[i]];
}
}
void dfs(ll num, ll k, ll sum)
{
if(sum < 0) return ;
if(num == 5) {
if(k & 1) ans -= f[sum];
else ans += f[sum];
return ;
}
dfs(num + 1, k + 1, sum - (d[num] + 1) * c[num]);
dfs(num + 1, k, sum);
return ;
}
int main()
{
scanf("%lld %lld %lld %lld %lld", &c[1], &c[2], &c[3], &c[4], &tot);
init();
while(tot --) {
scanf("%lld %lld %lld %lld %lld", &d[1], &d[2], &d[3], &d[4], &S);
ans = 0;
dfs(1, 0, S);
printf("%lld\n", ans);
}
return 0;
}