[HAOI2008]硬币购物
作者:互联网
一开始以为是一道智商税题目,结果发现似乎并没有那么简单。这道题给我提供了许多很有价值的思路。
首先多重背包是肯定会死的,二进制拆分似乎也并不是很有用处 (\(O(QN\log N)\)肯定超时),于是想到整体减空白。
整体是什么?显然会是没有限制,也就是所有硬币随便用时的方案数,此时直接暴力完全背包预处理即可。那空白呢?
空白的意义可以认为是强制硬币使用超量的情况。既然强制硬币超量,那么大可以先把超量硬币的面额减去,那么剩下的钱不管怎么花最后整体结果都是不合法的,而后者的计算就转换到了整体部分了,于是解决问题就只差个容斥了。可以枚举1到16,然后1的个数判加减即可,基本容斥。
#include<cstdio>
#define zczc
#define int long long
const int N=100010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
int m,n,now,ans,num,s[N],a[5],b[5];
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
s[0]=1;
for(int i=1;i<=4;i++){
read(a[i]);
for(int j=a[i];j<N;j++)s[j]+=s[j-a[i]];
}
read(m);
while(m--){
for(int i=1;i<=4;i++)read(b[i]);
ans=0;read(n);
for(int i=0;i<16;i++){
now=n,num=0;
for(int j=1;j<=4;j++){
if(i&(1<<j-1)){
now-=a[j]*(b[j]+1);
num++;
}
}
if(now>=0)ans+=((num&1)?-1:1)*s[now];
}
printf("%lld\n",ans);
}
return 0;
}
标签:超量,硬币,int,购物,wh,ans,HAOI2008,getchar 来源: https://www.cnblogs.com/dai-se-can-tian/p/16278865.html