【BZOJ1042】[HAOI2008]硬幣購物 容斥
阿新 • • 發佈:2017-08-15
namespace iostream cstring 容斥 pre 多少 while std sin
3 2 3 1 10
1000 2 2 2 900
27
【BZOJ10492】[HAOI2008]硬幣購物
Description
硬幣購物一共有4種硬幣。面值分別為c1,c2,c3,c4。某人去商店買東西,去了tot次。每次帶di枚ci硬幣,買si的價值的東西。請問每次有多少種付款方法。
Input
第一行 c1,c2,c3,c4,tot 下面tot行 d1,d2,d3,d4,s,其中di,s<=100000,tot<=1000
Output
每次的方法數
Sample Input
1 2 5 10 23 2 3 1 10
1000 2 2 2 900
Sample Output
427
題解:先跑一邊完全背包,然後對於每個詢問,我們考慮容斥。
ans=總數-至少一種硬幣超限的+至少兩種硬幣超限的-至少三種硬幣超限的+四種硬幣超限的。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; int n,sum,flag,s; ll f[100010]; ll ans; int c[10],d[10]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } void dfs(int x) { if(x==5) { ans+=flag*f[s-sum]; return ; } if(sum+c[x]*d[x]<=s) sum+=c[x]*d[x],flag=-flag,dfs(x+1),sum-=c[x]*d[x],flag=-flag; dfs(x+1); } int main() { int i,j; f[0]=1; for(i=1;i<=4;i++) { c[i]=rd(); for(j=c[i];j<=100000;j++) f[j]+=f[j-c[i]]; } n=rd(); for(i=1;i<=n;i++) { for(j=1;j<=4;j++) d[j]=rd()+1; s=rd(),flag=1,ans=0; dfs(1); printf("%lld\n",ans); } return 0; }
【BZOJ1042】[HAOI2008]硬幣購物 容斥