[HAOI2008] 硬币购物
08年是让我不淡定的一年。
这题我是完全没思路。
正解是容斥原理。
1:预处理完全背包,也就每种硬币可以使用无限次组成面值 S 的方案数。
2:ans = 总方案 - ( c1 超 + c2 超 + c3 超 + c4 超 ) + ( c1,c2 超 + c2,c3 超 +c3,c4 超 + c1,c4超) - ......
实现起来有用位运算实现的,但是 BYVoid 的递归实现比较好理解也更清晰一点。
// q.c
// ***
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int M=100000;
int c[5],d[5],tot,s;
long long f[M+10],ans;
void dfs(int x,int k,int sum) { // x表示第几种硬币,k表示几个超过限定数量的.
if(sum<0) return ; // 这里是严格小于0.
if(x==5) {
if(k&1) ans-=f[sum]; // 总方案减去不符合条件的,偶加奇减.
else ans+=f[sum];
return ;
}
dfs(x+1,k+1,sum-(d[x]+1)*c[x]); // 第x种硬币超过限定额度.
dfs(x+1,k,sum);
}
int main() {
freopen("coin.in","r",stdin);
freopen("coin.out","w",stdout);
for(int i=1;i<=4;i++) scanf("%d",&c[i]);
f[0]=1;
for(int i=1;i<=4;i++)
for(int j=c[i];j<=M;j++)
f[j]+=f[j-c[i]];
scanf("%d",&tot);
while(tot--) {
for(int i=1;i<=4;i++) scanf("%d",&d[i]);
scanf("%d",&s);
ans=0; dfs(1,0,s);
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号